เลือกภาพหลายภาพจากแกลเลอรี Android


114

ดังนั้นโดยทั่วไปสิ่งที่ฉันกำลังพยายามที่จะบรรลุจะเปิดGalleryใน Android multiple imagesและให้ผู้ใช้เลือก ตอนนี้คำถามนี้ถูกถามบ่อยแต่ฉันไม่พอใจกับคำตอบ ส่วนใหญ่เป็นเพราะฉันพบสิ่งที่น่าสนใจใน de docs ใน IDE ของฉัน (ฉันจะกลับมาในภายหลัง) และด้วยเหตุนี้ฉันจึงไม่ต้องการใช้อะแดปเตอร์ที่กำหนดเอง แต่เป็นเพียงวานิลลาเท่านั้น

ตอนนี้รหัสของฉันสำหรับเลือกภาพเดียวคือ:

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"), 1);

ตอนนี้ผู้คนใน SO และเว็บไซต์อื่น ๆ จะบอกคุณว่าคุณมี 2 ทางเลือก:

1) อย่าใช้ACTION_GET_CONTENTแต่ใช้ACTION_SEND_MULTIPLEแทน
อันนี้ใช้ไม่ได้ อันนี้เป็นไปตามเอกสารสำหรับsendingไฟล์ไม่ใช่retrievingและนั่นคือสิ่งที่ทำ เมื่อใช้ ACTION_SEND_MULTIPLE ฉันมีหน้าต่างเปิดขึ้นที่อุปกรณ์ของฉันซึ่งฉันต้องเลือกแอปพลิเคชันเพื่อส่งข้อมูลของฉันไป นั่นไม่ใช่สิ่งที่ฉันต้องการฉันจึงสงสัยว่าผู้คนประสบความสำเร็จด้วยวิธีนี้ได้อย่างไร .. ฉันพลาดอะไรไปหรือเปล่า

2) ใช้custom Gallery. ตอนนี้นี่เป็นตัวเลือกสุดท้ายของฉันที่ฉันจะพิจารณาเพราะฉันไม่ใช่สิ่งที่ฉันกำลังค้นหาเพราะฉันต้องจัดสไตล์ด้วยตัวเองและทำไมคุณไม่สามารถเลือกหลายภาพในแกลเลอรีวานิลลาได้?

ต้องมีตัวเลือกสำหรับการนี้ .. ตอนนี้สิ่งที่น่าสนใจในสิ่งที่ I'v พบคือ: ฉันพบนี้ในรายละเอียดของเอกสาร
ACTION_GET_CONTENT

หากผู้โทรสามารถจัดการรายการที่ส่งคืนได้หลายรายการ (ผู้ใช้ทำการเลือกหลายรายการ) ก็สามารถระบุ EXTRA_ALLOW_MULTIPLE เพื่อระบุสิ่งนี้ได้

นี่น่าสนใจทีเดียว ที่นี่พวกเขาอ้างถึงกรณีการใช้งานที่ผู้ใช้สามารถเลือกได้หลายรายการ?

ต่อมาพวกเขาพูดในเอกสาร:

คุณสามารถใช้ EXTRA_ALLOW_MULTIPLE เพื่ออนุญาตให้ผู้ใช้เลือกหลายรายการ

นี่ก็ค่อนข้างชัดเจนใช่มั้ย? นี่คือสิ่งที่ฉันต้องการ แต่คำถามต่อไปนี้ของฉันคือฉันจะวางสิ่งนี้ได้EXTRA_ALLOW_MULTIPLEที่ไหน? สิ่งที่น่าเศร้าคือฉันไม่พบสิ่งนี้ไม่มีที่ไหนในคำแนะนำสำหรับนักพัฒนาแอนดรอยด์และสิ่งนี้ไม่ได้ถูกกำหนดให้เป็นค่าคงที่ในคลาส INTENT

มีใครช่วยฉันได้EXTRA_ALLOW_MULTIPLEบ้าง




1
โซลูชัน @KyleShank ใช้ได้ผลสำหรับฉัน การตั้งค่าEXTRA_ALLOW_MULTIPLEให้คุณเลือกหลายรายการ รับ URI โดยเรียกgetClipData()เจตนาที่ส่งคืนเข้าonActivityResultมา ปัญหาเดียวคือวิดเจ็ตแกลเลอรีไม่อนุญาตให้เลือกหลายรายการ ในกรณีนี้การคลิกภาพใด ๆ จะเป็นการสิ้นสุดตัวเลือกและคุณสามารถรับ URI (ของรายการเดียว) ได้โดยเรียกร้องให้getDataส่งคืนเจตนา
Tanweer Alam

คำตอบ:


122

อ็อพชัน EXTRA_ALLOW_MULTIPLE ถูกตั้งค่าตามความตั้งใจโดยใช้เมธอด Intent.putExtra ():

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

รหัสของคุณด้านบนควรมีลักษณะดังนี้:

Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"), 1);

หมายเหตุ: EXTRA_ALLOW_MULTIPLEตัวเลือกนี้ใช้ได้เฉพาะใน Android API 18 ขึ้นไป


ฉันรู้สิ่งนี้ แต่ที่ฉันพูดถึงในคำตอบของฉัน: "สิ่งที่น่าเศร้าคือฉันไม่พบสิ่งนี้ไม่พบที่ไหนในคู่มือ developer.android และสิ่งนี้ไม่ได้กำหนดเป็นค่าคงที่ในคลาส INTENT" IDE ของฉันไม่รู้จัก Intent.EXTRA_ALLOW_MULTIPLE ฉันติดตั้ง API ระดับ 18 แล้ว IDE ของฉันบอกว่า: "EXTRA_ALLOW_MULTIPLE ไม่สามารถแก้ไขได้หรือไม่ใช่ฟิลด์"
Dion Segijn

Intent.putExtra (Intent.EXTRA_ALLOW_MULTIPLE จริง); ใช้โปรแกรมจำลองไม่รองรับการเลือกหลายรายการ
qinmiao

11
เลือกภาพหลายภาพ แต่จะรับ URL ภาพจากผลกิจกรรมได้อย่างไร ????
John

4
สิ่งนี้เป็นการเปิดตัวเลือกรูปภาพและอนุญาตให้ฉันเลือกหลายภาพ แต่ฉันไม่รู้วิธีรับ URL ใน onActivityResult
Tom Kincaid

5
คุณสามารถรับ URL ในผลลัพธ์Intent.getClipDataได้ มีอาร์เรย์ของรายการ ClipData
Tam Huynh

71

กำหนดตัวแปรเหล่านี้ในคลาส:

int PICK_IMAGE_MULTIPLE = 1; 
String imageEncoded;    
List<String> imagesEncodedList;

สมมติว่าเมื่อคลิกที่ปุ่มควรเปิดแกลเลอรีเพื่อเลือกภาพ

 Intent intent = new Intent();
 intent.setType("image/*");
 intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
 intent.setAction(Intent.ACTION_GET_CONTENT);
 startActivityForResult(Intent.createChooser(intent,"Select Picture"), PICK_IMAGE_MULTIPLE);

จากนั้นคุณควรแทนที่เมธอด onActivityResult

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    try {
        // When an Image is picked
        if (requestCode == PICK_IMAGE_MULTIPLE && resultCode == RESULT_OK
                    && null != data) {
            // Get the Image from data

            String[] filePathColumn = { MediaStore.Images.Media.DATA };
            imagesEncodedList = new ArrayList<String>();
            if(data.getData()!=null){

                Uri mImageUri=data.getData();

                // Get the cursor
                Cursor cursor = getContentResolver().query(mImageUri,
                            filePathColumn, null, null, null);
                // Move to first row
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                imageEncoded  = cursor.getString(columnIndex);
                cursor.close();

            } else {
                if (data.getClipData() != null) {
                    ClipData mClipData = data.getClipData();
                    ArrayList<Uri> mArrayUri = new ArrayList<Uri>();
                    for (int i = 0; i < mClipData.getItemCount(); i++) {

                        ClipData.Item item = mClipData.getItemAt(i);
                        Uri uri = item.getUri();
                        mArrayUri.add(uri);
                        // Get the cursor
                        Cursor cursor = getContentResolver().query(uri, filePathColumn, null, null, null);
                        // Move to first row
                        cursor.moveToFirst();

                        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                        imageEncoded  = cursor.getString(columnIndex);
                        imagesEncodedList.add(imageEncoded);
                        cursor.close();

                    }
                    Log.v("LOG_TAG", "Selected Images" + mArrayUri.size());
                }
            }
        } else {
            Toast.makeText(this, "You haven't picked Image",
                        Toast.LENGTH_LONG).show();
        }
    } catch (Exception e) {
        Toast.makeText(this, "Something went wrong", Toast.LENGTH_LONG)
                    .show();
    }

    super.onActivityResult(requestCode, resultCode, data);
}

หมายเหตุ: แกลเลอรีไม่ได้ให้ความสามารถในการเลือกหลายภาพดังนั้นเราจึงเปิดสตูดิโอภาพทั้งหมดที่คุณสามารถเลือกหลายภาพจากพวกเขาได้ และอย่าลืมเพิ่มสิทธิ์ในไฟล์ Manifest ของคุณ

สำคัญมาก: getData (); เพื่อรับภาพเดียวและฉันเก็บไว้ที่นี่ใน imageEncoded String หากผู้ใช้เลือกหลายภาพควรเก็บไว้ในรายการ

ดังนั้นคุณต้องตรวจสอบว่าอันไหนเป็นโมฆะเพื่อใช้อีกอัน

ขอให้คุณมีความสุขและพยายามกับคนอื่น ๆ


ฉันข้าม "Intent.setType (" image / * ");" และส่งผู้ใช้ไปที่รูปภาพโดยตรงแทนที่จะให้โอกาสผู้ใช้ไปที่แกลเลอรีซึ่งไม่อนุญาตให้เลือกหลายภาพ ไม่แน่ใจว่าเป็นเพราะเหตุนี้หรือไม่ getData () ของฉันไม่ส่งคืนค่าว่างดังนั้นฉันจึงใช้ getClipData เฉพาะสำหรับการเลือกภาพเดียวและหลายภาพ
Johnny Wu

1
แค่ใช้ part data.getClipData () ก็เพียงพอไม่ต้องตรวจสอบ data.getData ()
truongnm

&& null! = data ??
Odaym

8
Uri uri = content: //com.android.providers.media.documents/document/image%3A772 uri มีข้อมูล แต่ cursor.getString คืนค่า null ให้ฉัน imageEncoded = cursor.getString (columnIndex);
Muhammad Zubair Ashraf

2
มันมีประโยชน์ แต่ฉันต้องเสริมด้วยฟังก์ชันเหล่านี้สำหรับ getPath: stackoverflow.com/a/20559175/6141959
Geynen

31

คำตอบเหล่านี้จำนวนมากมีความคล้ายคลึงกัน แต่ส่วนที่สำคัญที่สุดที่อยู่ในonActivityResultนั้นขาดหายไปให้ตรวจสอบว่าdata.getClipDataเป็นโมฆะหรือไม่ก่อนตรวจสอบdata.getData

รหัสสำหรับเรียกตัวเลือกไฟล์:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*"); //allows any image file type. Change * to specific extension to limit it
//**The following line is the important one!
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), SELECT_PICTURES); //SELECT_PICTURES is simply a global int used to check the calling intent in onActivityResult

รหัสเพื่อรับภาพทั้งหมดที่เลือก:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == SELECT_PICTURES) {
        if(resultCode == Activity.RESULT_OK) {
            if(data.getClipData() != null) {
                int count = data.getClipData().getItemCount(); //evaluate the count before the for loop --- otherwise, the count is evaluated every loop.
                for(int i = 0; i < count; i++)  
                    Uri imageUri = data.getClipData().getItemAt(i).getUri();
                    //do something with the image (save it to some directory or whatever you need to do with it here) 
                }
            } else if(data.getData() != null) {
                String imagePath = data.getData().getPath();
                //do something with the image (save it to some directory or whatever you need to do with it here)
            }
        }
    }
}

โปรดทราบว่าตัวเลือกของ Android มีรูปภาพและแกลเลอรีในอุปกรณ์บางรุ่น รูปภาพอนุญาตให้เลือกหลายภาพ แกลเลอรีอนุญาตครั้งละหนึ่งรายการ


getClipData () คืออะไร? data.getData ไม่เพียงพอหรือไม่
Adi

1
ในอุปกรณ์ Samsung บางรุ่นผลลัพธ์จะแตกต่างจากอุปกรณ์ที่ไม่ใช่ของ Samsung หากผู้ใช้เลือกหลายไฟล์getData()บางครั้งจะไม่เป็นโมฆะ แต่จะมีUri เพียงไฟล์เดียว หากคุณต้องการจัดการเมื่อผู้ใช้เลือกไฟล์หลายไฟล์ให้ตรวจสอบgetClipData()ก่อนgetData()- หากข้อมูลคลิปไม่เป็นโมฆะผู้ใช้อาจเลือกหลายภาพ การจัดการ getClipData ก่อน getData แต่การจัดการทั้งสองกรณีมีความสำคัญในการรองรับอุปกรณ์ที่แตกต่างกันในขณะที่ยังคงอนุญาตหลาย Uris
Mira_Cole

@Mira_Code ฉันจะตั้งค่าภาพที่เลือกเป็นมุมมองภาพอื่นได้อย่างไร
Hasnain Ghias

20

ฉันหวังว่าคำตอบนี้จะไม่สาย เนื่องจากวิดเจ็ตแกลเลอรีไม่รองรับการเลือกหลายรายการตามค่าเริ่มต้น แต่คุณสามารถกำหนดมุมมองตารางเองซึ่งยอมรับความตั้งใจหลายอย่างของคุณได้ อีกทางเลือกหนึ่งคือการขยายมุมมองแกลเลอรีและเพิ่มรหัสของคุณเองเพื่อให้สามารถเลือกได้หลายรายการ
นี่คือไลบรารีง่ายๆที่สามารถทำได้: https://github.com/luminousman/MultipleImagePick

อัปเดต :
จากความคิดเห็นของ @ ilsy CustomGalleryActivityในการใช้ไลบรารีนี้manageQueryซึ่งเลิกใช้แล้วดังนั้นจึงควรเปลี่ยนเป็นgetContentResolver().query()และcursor.close()ชอบคำตอบนี้


@ R4j ใช่และฉันเขียนเกี่ยวกับเรื่องนั้น: ห้องสมุดไม่พร้อมใช้งานในโครงการ ต้องการการอัปเดตมากมายเพื่อเริ่มใช้งาน และเกี่ยวกับการอัปเดตของคุณ: อย่าใช้getContentResolver().query()ในเธรด UI อ่านเกี่ยวกับ Loaders และ Support Library
mbelsky

.cacheOnDisc()เลิกใช้แล้วดังนั้นให้เปลี่ยนเป็น.cacheOnDisc(true)บูลีนพารามิเตอร์
Pratik Butani

5

เริ่มต้นอินสแตนซ์:

private String imagePath;
private List<String> imagePathList;

ในonActivityResultคุณต้องเขียนสิ่งนี้บล็อก If-else 2 หนึ่งสำหรับภาพเดียวและอีกภาพสำหรับหลายภาพ

if (requestCode == GALLERY_CODE && resultCode == RESULT_OK  && data != null){

    imagePathList = new ArrayList<>();

    if(data.getClipData() != null){

        int count = data.getClipData().getItemCount();
        for (int i=0; i<count; i++){

            Uri imageUri = data.getClipData().getItemAt(i).getUri();
            getImageFilePath(imageUri);
        }
    }
    else if(data.getData() != null){

        Uri imgUri = data.getData();
        getImageFilePath(imgUri);
    }
}

ส่วนที่สำคัญที่สุดรับเส้นทางภาพจาก uri :

public void getImageFilePath(Uri uri) {

    File file = new File(uri.getPath());
    String[] filePath = file.getPath().split(":");
    String image_id = filePath[filePath.length - 1];

    Cursor cursor = getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{image_id}, null);
    if (cursor!=null) {
        cursor.moveToFirst();
        imagePath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        imagePathList.add(imagePath);
        cursor.close();
    }
}

หวังว่านี่จะช่วยคุณได้


1

ฉันได้ค่าว่างจากไฟล์Cursor. จากนั้นพบวิธีการแปลงUriเป็นBitmapที่ทำงานได้อย่างสมบูรณ์

นี่คือวิธีแก้ปัญหาที่เหมาะกับฉัน:

@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
{

    if (resultCode == Activity.RESULT_OK) {

        if (requestCode == YOUR_REQUEST_CODE) {

            if (data != null) {

                if (data.getData() != null) {

                    Uri contentURI = data.getData();
                    ex_one.setImageURI(contentURI);

                    Log.d(TAG, "onActivityResult: " + contentURI.toString());
                    try {

                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), contentURI);

                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                } else {

                    if (data.getClipData() != null) {
                        ClipData mClipData = data.getClipData();
                        ArrayList<Uri> mArrayUri = new ArrayList<Uri>();
                        for (int i = 0; i < mClipData.getItemCount(); i++) {

                            ClipData.Item item = mClipData.getItemAt(i);
                            Uri uri = item.getUri();
                            try {
                                Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }

                        }
                    }

                }

            }

        }

    }

}

0

สวัสดีโค้ดด้านล่างใช้งานได้ดี

 Cursor imagecursor1 = managedQuery(
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null,
    null, orderBy + " DESC");

   this.imageUrls = new ArrayList<String>();
  imageUrls.size();

   for (int i = 0; i < imagecursor1.getCount(); i++) {
   imagecursor1.moveToPosition(i);
   int dataColumnIndex = imagecursor1
     .getColumnIndex(MediaStore.Images.Media.DATA);
   imageUrls.add(imagecursor1.getString(dataColumnIndex));
  }

   options = new DisplayImageOptions.Builder()
  .showStubImage(R.drawable.stub_image)
  .showImageForEmptyUri(R.drawable.image_for_empty_url)
  .cacheInMemory().cacheOnDisc().build();

   imageAdapter = new ImageAdapter(this, imageUrls);

   gridView = (GridView) findViewById(R.id.PhoneImageGrid);
  gridView.setAdapter(imageAdapter);

คุณต้องการคำชี้แจงเพิ่มเติม http://mylearnandroid.blogspot.in/2014/02/multiple-choose-custom-gallery.html


1
ถ้ามันใช้งานได้ก็ใช้ได้ เป็นการดีที่จะชี้ให้เห็นรหัสที่เลิกใช้งาน แต่ตราบใดที่คุณใช้งานโดยไม่มีปัญหาใด ๆ ก็ใช้ได้ดี สิ่งสำคัญคือต้องทราบว่าเหตุใดจึงเลิกใช้งานไม่ว่าจะเป็นปัญหาด้านความปลอดภัยรหัสที่ใหม่กว่าจึงมีประสิทธิภาพมากขึ้น ฯลฯ แต่เนื่องจากแอป Android ส่งต่อรหัสที่เลิกใช้งานที่เข้ากันได้จะยังคงใช้งานได้ในอนาคต
JStephen

0

ฉันก็มีปัญหาเดียวกัน ฉันยังต้องการให้ผู้ใช้สามารถถ่ายภาพได้อย่างง่ายดายในขณะที่เลือกรูปภาพจากแกลเลอรี ไม่พบวิธีดั้งเดิมในการทำเช่นนี้ดังนั้นฉันจึงตัดสินใจสร้างโครงการโอเพนซอร์ซ มันเหมือนกับ MultipleImagePick แต่เป็นวิธีที่ดีกว่าในการใช้งาน

https://github.com/giljulio/android-multiple-image-picker

private static final RESULT_CODE_PICKER_IMAGES = 9000;


Intent intent = new Intent(this, SmartImagePicker.class);
startActivityForResult(intent, RESULT_CODE_PICKER_IMAGES);


@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode){
        case RESULT_CODE_PICKER_IMAGES:
            if(resultCode == Activity.RESULT_OK){
                Parcelable[] parcelableUris = data.getParcelableArrayExtra(ImagePickerActivity.TAG_IMAGE_URI);

                //Java doesn't allow array casting, this is a little hack
                Uri[] uris = new Uri[parcelableUris.length];
                System.arraycopy(parcelableUris, 0, uris, 0, parcelableUris.length);

                //Do something with the uris array
            }
            break;

        default:
            super.onActivityResult(requestCode, resultCode, data);
            break;
    }
}

0

ลองใช้IntentChooser ตัวนี้ เพียงเพิ่มโค้ดบางบรรทัดฉันก็จัดการที่เหลือให้คุณเอง

private void startImageChooserActivity() {
    Intent intent = ImageChooserMaker.newChooser(MainActivity.this)
            .add(new ImageChooser(true))
            .create("Select Image");
    startActivityForResult(intent, REQUEST_IMAGE_CHOOSER);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_IMAGE_CHOOSER && resultCode == RESULT_OK) {
        List<Uri> imageUris = ImageChooserMaker.getPickMultipleImageResultUris(this, data);
    }
}

ป.ล. : ดังที่ได้กล่าวไว้ในคำตอบข้างต้น EXTRA_ALLOW_MULTIPLE ใช้ได้เฉพาะกับ API> = 18 และแอปแกลเลอรีบางแอปไม่ทำให้คุณลักษณะนี้ใช้งานได้ (Google Photos และเอกสาร ( com.android.documentsui) ใช้งานได้


ไม่ให้ฉันเลือกหลายภาพแม้ว่าจะเพิ่มintent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Scorpion
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.