Chọn nhiều hình ảnh từ thư viện android


114

Vì vậy, về cơ bản những gì tôi đang cố gắng đạt được là mở Gallerytrong Android và để người dùng chọn multiple images. Bây giờ câu hỏi này đã được hỏi thường xuyên nhưng tôi không hài lòng với câu trả lời. Chủ yếu là vì tôi tìm thấy thứ gì đó thú vị trong de docs trong IDE của mình (tôi sẽ quay lại điều này sau) và do đó tôi không muốn sử dụng bộ điều hợp tùy chỉnh mà chỉ sử dụng bộ điều hợp vani.

Bây giờ mã của tôi để chọn một hình ảnh là:

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

Bây giờ Mọi người trên SO và các trang web khác sẽ cho bạn biết bạn có 2 lựa chọn:

1) Không sử dụng ACTION_GET_CONTENTACTION_SEND_MULTIPLEthay vào đó.
Cái này không hoạt động. Đây là theo tài liệu dành cho sendingtệp chứ không phải retrievingvà đó chính xác là những gì nó làm. Khi sử dụng ACTION_SEND_MULTIPLE, thiết bị của tôi đã mở một cửa sổ, nơi tôi phải chọn một ứng dụng để gửi dữ liệu của mình. Đó không phải là những gì tôi muốn, vì vậy tôi tự hỏi làm thế nào mọi người đạt được điều này với giải pháp này .. Tôi có bỏ lỡ điều gì không?

2) Thực hiện một custom Gallery. Bây giờ đây là lựa chọn cuối cùng của tôi, tôi sẽ xem xét bởi vì đó không phải là thứ tôi đang tìm kiếm bởi vì tôi phải tự tạo kiểu cho nó VÀ tại sao bạn không thể chọn nhiều hình ảnh trong bộ sưu tập vani?

Phải có một lựa chọn cho việc này .. Bây giờ điều thú vị mà tôi tìm thấy là cái này:
Tôi tìm thấy cái này trong phần mô tả tài liệu của ACTION_GET_CONTENT.

Nếu người gọi có thể xử lý nhiều mục trả lại (người dùng thực hiện nhiều lựa chọn), thì người gọi có thể chỉ định EXTRA_ALLOW_MULTIPLE để chỉ ra điều này.

Điều này khá thú vị. Ở đây họ đang đề cập đến trường hợp sử dụng mà người dùng có thể chọn nhiều mục?

Sau đó, họ nói trong tài liệu:

Bạn có thể sử dụng EXTRA_ALLOW_MULTIPLE để cho phép người dùng chọn nhiều mục.

Vì vậy, điều này là khá rõ ràng phải không? Đây là những gì tôi cần. Nhưng câu hỏi sau của tôi là: Tôi có thể đặt cái này ở EXTRA_ALLOW_MULTIPLEđâu? Điều đáng buồn là tôi không thể tìm thấy điều này không có ở đâu trong hướng dẫn Develop.android và điều này cũng không được định nghĩa là một hằng số trong lớp INTENT.

Ai có thể giúp tôi với điều này EXTRA_ALLOW_MULTIPLE?




1
Giải pháp @KyleShank đã phù hợp với tôi. Cài đặt EXTRA_ALLOW_MULTIPLEcho phép bạn chọn nhiều mục. Nhận các URI bằng cách gọi getClipData()ý định trả lại trong onActivityResult. Vấn đề duy nhất là widget thư viện sẽ không cho phép nhiều lựa chọn. Trong trường hợp đó click bất kỳ hình ảnh sẽ kết thúc choser và bạn có thể nhận được URI (mặt hàng duy nhất) bằng cách gọi getDatatrên trở ý định
Tanweer Alam

Câu trả lời:


122

Tùy chọn EXTRA_ALLOW_MULTIPLE được đặt trên ý định thông qua phương thức Intent.putExtra ():

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

Mã của bạn ở trên sẽ giống như sau:

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);

Lưu ý: EXTRA_ALLOW_MULTIPLEtùy chọn này chỉ khả dụng trong Android API 18 trở lên.


Tôi biết điều này nhưng khi tôi đề cập trong câu trả lời của mình: "Điều đáng buồn là tôi không thể tìm thấy điều này không có ở đâu trong hướng dẫn Develop.android và điều này cũng không được định nghĩa là một hằng số trong lớp INTENT." IDE của tôi không nhận dạng được Intent.EXTRA_ALLOW_MULTIPLE. Tôi đã cài đặt API cấp 18. IDE của tôi cho biết: "Không thể giải quyết EXTRA_ALLOW_MULTIPLE hoặc không phải là trường"
Dion Segijn

ý định.putExtra (Intent.EXTRA_ALLOW_MULTIPLE, true); sử dụng giả lập, không hỗ trợ nhiều lựa chọn.
qinmiao

11
Nó chọn nhiều hình ảnh. nhưng làm thế nào để lấy url hình ảnh từ kết quả Hoạt động ????
John

4
Thao tác này khởi chạy bộ chọn hình ảnh và cho phép tôi chọn nhiều hình ảnh, nhưng tôi không biết cách lấy các url trong onActivityResult.
Tom Kincaid

5
Bạn có thể lấy các url trong kết quả Intent.getClipData. Nó có mảng ClipData Item.
Tam Huynh

71

Xác định các biến này trong lớp:

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

Giả sử rằng onClick vào một nút, nó sẽ mở thư viện để chọn hình ảnh

 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);

Sau đó, bạn nên ghi đè Phương thức 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);
}

LƯU Ý RẰNG: thư viện không cung cấp cho bạn khả năng chọn nhiều hình ảnh vì vậy chúng tôi ở đây mở tất cả studio hình ảnh mà bạn có thể chọn nhiều hình ảnh từ chúng. và đừng quên thêm quyền vào tệp kê khai của bạn

RẤT QUAN TRỌNG: getData (); để có được một hình ảnh duy nhất và tôi đã lưu trữ nó ở đây trong imageEncoded String nếu người dùng chọn nhiều hình ảnh thì chúng sẽ được lưu trữ trong danh sách

Vì vậy, bạn phải kiểm tra xem cái nào là null để sử dụng cái kia

Chúc bạn có một thử tốt đẹp và những người khác


Tôi đã bỏ qua "ý định.setType (" hình ảnh / * ");" và nó đưa người dùng trực tiếp đến Ảnh thay vì cho người dùng cơ hội vào Thư viện, nơi không cho phép chọn nhiều ảnh. Không chắc liệu có phải vì vậy không, getData () của tôi không bao giờ trả về null, vì vậy tôi đã kết thúc bằng cách sử dụng getClipData dành riêng cho cả lựa chọn hình ảnh đơn và nhiều hình ảnh.
Johnny Wu

1
chỉ cần sử dụng phần data.getClipData () là đủ, không cần kiểm tra data.getData ()
truongnm

&& null! = data ??
Odaym

8
Uri uri = content: //com.android.providers.media.documents/document/image%3A772 uri có dữ liệu nhưng cursor.getString trả về null cho tôi imageEncoded = cursor.getString (columnIndex);
Muhammad Zubair Ashraf

2
Nó rất hữu ích, nhưng tôi phải bổ sung các chức năng này cho getPath: stackoverflow.com/a/20559175/6141959
Geynen

30

Rất nhiều câu trả lời có điểm giống nhau nhưng tất cả đều thiếu phần quan trọng nhất trong đó onActivityResult, hãy kiểm tra xem data.getClipDatacó rỗng trước không kiểm tradata.getData

Mã để gọi trình chọn tệp:

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

Mã để chọn tất cả các hình ảnh:

@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)
            }
        }
    }
}

Lưu ý rằng trình chọn của Android có sẵn Ảnh và Thư viện trên một số thiết bị. Ảnh cho phép chọn nhiều ảnh. Thư viện chỉ cho phép một cái tại một thời điểm.


getClipData () là gì? data.getData không đủ?
adi

1
Ở một số thiết bị Samsung, kết quả sẽ khác so với các thiết bị không phải của Samsung. Nếu người dùng chọn nhiều tệp, getData()đôi khi sẽ KHÔNG rỗng mà sẽ chỉ có một Uri. Nếu bạn muốn xử lý khi người dùng chọn nhiều tệp, hãy kiểm tra getClipData()trước getData()- nếu dữ liệu clip không rỗng thì có thể người dùng đã chọn nhiều ảnh. Xử lý getClipData trước getData nhưng xử lý cả hai trường hợp đều quan trọng để hỗ trợ các thiết bị khác nhau trong khi vẫn cho phép nhiều Uris.
Mira_Cole

@Mira_Code Làm cách nào để đặt các hình ảnh đã chọn thành các chế độ xem hình ảnh khác nhau.
Hasnain Ghias

20

Tôi hy vọng câu trả lời này không muộn. Bởi vì tiện ích thư viện không hỗ trợ nhiều lựa chọn theo mặc định, nhưng bạn có thể tùy chỉnh chế độ xem lưới chấp nhận ý định nhiều lựa chọn của bạn. Tùy chọn khác là mở rộng chế độ xem thư viện và thêm mã của riêng bạn để cho phép nhiều lựa chọn.
Đây là thư viện đơn giản có thể làm được: https://github.com/luminousman/MultipleImagePick

Cập nhật :
Từ nhận xét của @ ilsy, CustomGalleryActivity trong thư viện này sử dụng manageQuery, không được dùng nữa, vì vậy nó nên được đổi thành getContentResolver().query()cursor.close()thích câu trả lời này


@ R4j Có và tôi đã viết về điều đó: thư viện chưa sẵn sàng để sử dụng trong các dự án. Cần nhiều bản cập nhật để bắt đầu sử dụng nó. Và về bản cập nhật của bạn: không sử dụng getContentResolver().query()trong chuỗi giao diện người dùng. Đọc về Bộ tải và Thư viện hỗ trợ.
mbelsky

.cacheOnDisc()cũng bị phản đối nên thay đổi nó thành .cacheOnDisc(true)với param boolean
Pratik Butani

5

Khởi tạo phiên bản:

private String imagePath;
private List<String> imagePathList;

Trong onActivityResult Bạn phải viết khối If-else 2 này. Một cho một hình ảnh và một cho nhiều hình ảnh.

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);
    }
}

Phần quan trọng nhất, Lấy đường dẫn hình ảnh từ 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();
    }
}

Hy vọng điều này có thể giúp bạn.


1

Tôi nhận được null từ Cursor. Sau đó, tìm ra một giải pháp để chuyển đổi Urithành Bitmaphoạt động hoàn hảo.

Đây là giải pháp phù hợp với tôi:

@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

Xin chào mã dưới đây đang hoạt động tốt.

 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);

Bạn muốn làm rõ hơn. http://mylearnandroid.blogspot.in/2014/02/multiple-choose-custom-gallery.html


1
nếu nó hoạt động, nó tốt. Thật tốt khi chỉ ra mã không dùng nữa, nhưng miễn là bạn đang sử dụng nó mà không gặp bất kỳ vấn đề gì thì nó vẫn tốt. Điều quan trọng là phải biết lý do tại sao nó không được dùng nữa, cho dù đó là vấn đề bảo mật, mã mới hơn có hiệu quả hơn, v.v. Nhưng vì các ứng dụng Android tương thích về phía trước nên mã không dùng nữa sẽ vẫn hoạt động trong tương lai.
JStephen

0

Tôi cũng có cùng một vấn đề. Tôi cũng muốn người dùng có thể chụp ảnh dễ dàng trong khi chọn ảnh từ thư viện. Không thể tìm thấy một cách nguyên bản để làm điều này, do đó tôi quyết định thực hiện một dự án nguồn mở. Nó giống như MultipleImagePick nhưng chỉ là cách triển khai nó tốt hơn.

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

Hãy thử một IntentChooser này . Chỉ cần thêm một số dòng mã, tôi đã làm phần còn lại cho bạn.

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);
    }
}

Tái bút: như đã đề cập ở các câu trả lời ở trên, EXTRA_ALLOW_MULTIPLE chỉ khả dụng cho API> = 18. Và một số ứng dụng thư viện không cung cấp tính năng này (Google Photos và Documents ( com.android.documentsui) hoạt động.


Không cho tôi chọn nhiều hình ảnh mặc dù bổ sungintent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Scorpion
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.