Android galerisinden birden fazla resim seçin


114

Yani temelde elde etmeye çalıştığım şey GalleryAndroid'de açmak ve kullanıcının seçmesine izin vermek multiple images. Şimdi bu soru sıkça soruldu ama cevaplardan memnun değilim. Temelde, IDE'mde de docs'da ilginç bir şey bulduğum için (buna daha sonra geri döneceğim) ve bu nedenle özel bir adaptör kullanmak istemiyorum, sadece vanilya kullanmak istiyorum.

Şimdi bir resim seçme kodum:

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

Şimdi SO'daki ve diğer web sitelerindeki Kişiler size 2 seçeneğiniz olduğunu söyleyecek:

1) kullanmayın ACTION_GET_CONTENTama ACTION_SEND_MULTIPLEbunun yerine.
Bu çalışmıyor. Bu sendingdosya belgelerine göre değilretrieving ve tam olarak yaptığı şey bu. ACTION_SEND_MULTIPLE kullanırken, cihazımda verilerimi göndermek için bir uygulama seçmem gereken bir pencere açtım. İstediğim bu değil, bu yüzden insanlar bu çözümle bunu nasıl başardılar merak ediyorum .. Bir şeyi özlüyor muyum?

2) Bir custom Gallery. Şimdi bu benim düşüneceğim son seçeneğim çünkü aradığım şey bu değil çünkü onu kendim biçimlendirmem gerekiyor VE neden vanilya galerisinde birden fazla resim seçemiyorsunuz?

Bunun için bir seçenek olmalı .. Şimdi bulduğum ilginç şey şudur:
Bunu belgelerin açıklamasında buldum ACTION_GET_CONTENT.

Arayan, birden çok iade edilen öğeyi işleyebiliyorsa (kullanıcı, birden çok seçim gerçekleştiriyorsa), bunu belirtmek için EXTRA_ALLOW_MULTIPLE öğesini belirleyebilir.

Bu oldukça ilginç. Burada, bir kullanıcının birden çok öğe seçebileceği kullanım senaryosuna atıfta bulunuyorlar?

Daha sonra belgelerde şöyle derler:

Kullanıcının birden çok öğe seçmesine izin vermek için EXTRA_ALLOW_MULTIPLE kullanabilirsiniz.

Yani bu oldukça açık değil mi? İhtiyacım olan bu. Ama şu sorum şu: Bunu nereye koyabilirim EXTRA_ALLOW_MULTIPLE? Üzücü olan şey, geliştiriciler.android kılavuzunda bunu hiçbir yerde bulamıyorum ve ayrıca bu, INTENT sınıfında sabit olarak tanımlanmıyor.

Bana bu konuda yardımcı olabilecek biri var mı EXTRA_ALLOW_MULTIPLE?




1
@KyleShank çözümü benim için çalıştı. Ayar EXTRA_ALLOW_MULTIPLE, birden çok öğe seçmenize izin verir. getClipData()Döndürülen amacı çağırarak URI'leri alın onActivityResult. Tek sorun, galeri widget'ının çoklu seçime izin vermemesidir. Bu durumda, herhangi bir resme tıklamak seçiciyi bitirir ve URI'yi (tek öğenin) getDatageri dönen niyet üzerine çağırarak alabilirsiniz
Tanweer Alam

Yanıtlar:


122

EXTRA_ALLOW_MULTIPLE seçeneği, Intent.putExtra () yöntemi aracılığıyla amaç üzerinde ayarlanır:

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

Yukarıdaki kodunuz şöyle görünmelidir:

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

Not: Bu EXTRA_ALLOW_MULTIPLEseçenek yalnızca Android API 18 ve sonraki sürümlerde mevcuttur.


Bunu biliyorum ama cevabımda da bahsettiğim gibi: "Üzücü olan şey, bunu Developers.android kılavuzunda hiçbir yerde bulamıyorum ve ayrıca bu INTENT sınıfında bir sabit olarak tanımlanmıyor." IDE'm Intent.EXTRA_ALLOW_MULTIPLE'ı tanımıyor. API seviyesi 18 kurulu. IDE'm diyor ki: "EXTRA_ALLOW_MULTIPLE çözülemiyor veya alan değil"
Dion Segijn

intent.putExtra (Intent.EXTRA_ALLOW_MULTIPLE, doğru); öykünücü kullanın, çoklu seçimi desteklemeyin.
qinmiao

11
Çoklu görüntüyü seçmektir. ama görsel url'sini Etkinlik sonucundan nasıl alabilirim ????
John

4
Bu, resim seçiciyi başlatır ve birden fazla resim seçmeme izin verir, ancak url'leri onActivityResult'a nasıl alacağımı bilmiyorum.
Tom Kincaid

5
Sonuçta url'leri alabilirsiniz Intent.getClipData. ClipData Öğesi dizisine sahiptir.
Tam Huynh

71

Bu değişkenleri sınıfta tanımlayın:

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

Farz edelim ki onClick onClick, görselleri seçmek için galeri açmalıdır.

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

Daha sonra onActivityResult Yöntemini geçersiz kılmalısınız

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

BUNU NOT ET: galeri size çoklu görüntüleri seçme olanağı sağlamaz, bu nedenle burada çoklu görüntüleri seçebileceğiniz tüm görüntü stüdyosunu açıyoruz. ve bildiriminize izinleri eklemeyi unutmayın

ÇOK ÖNEMLİ: getData (); tek bir görüntü elde etmek için ve ben burada imageEncoded String'de depoladım, eğer kullanıcı çoklu görüntüleri seçerse, listede saklanmalıdırlar

Öyleyse, diğerini kullanmak için hangisinin boş olduğunu kontrol etmelisiniz.

İyi denemeni dilerim ve başkalarına


"İntent.setType (" image / * ");" ve kullanıcıya çoklu resim seçimine izin vermeyen Galeri'ye gitme şansı vermek yerine, kullanıcıları doğrudan Fotoğraf'a gönderir. Bunun nedeni olup olmadığından emin değilim, getData () işlevim hiçbir zaman boş döndürmez, bu yüzden getClipData'yı hem tekli hem de çoklu görüntü seçimi için özel olarak kullandım.
Johnny Wu

1
sadece data.getClipData () parçasını kullanın yeterli, data.getData () 'yı kontrol etmeye gerek yok
truongnm

&& null! = veri ??
Odaym

8
Uri uri = içerik: //com.android.providers.media.documents/document/image%3A772 uri'de veri var, ancak cursor.getString bana boş dönüyor imageEncoded = cursor.getString (columnIndex);
Muhammad Zubair Ashraf

2
Yararlıydı, ancak getPath için şu işlevleri tamamlamam gerekiyordu: stackoverflow.com/a/20559175/6141959
Geynen

31

Bu cevapların çoğunun benzerlikleri var ama hepsinde en önemli kısım eksik onActivityResult, kontrol etmeden öncedata.getClipData boş olup olmadığını kontrol edindata.getData

Dosya seçiciyi çağıracak kod:

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

Seçilen tüm resimleri alma kodu :

@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 seçicisinin bazı cihazlarda Fotoğraflar ve Galeri'ye sahip olduğunu unutmayın. Fotoğraflar, birden fazla görüntünün seçilmesine izin verir. Galeri bir seferde yalnızca birine izin verir.


getClipData () nedir? data.getData yeterli değil mi?
adi

1
Bazı Samsung cihazlarında, sonuçlar Samsung olmayan cihazlardan farklı olacaktır. Kullanıcı birden fazla dosya seçerse, getData()bazen boş OLMAYACAK ancak yalnızca bir URI'ya sahip olacaktır . Bir kullanıcı birden fazla dosya seçtiğinde işlemek istiyorsanız , getClipData()önce kontrol edin getData()- klip verileri boş değilse, kullanıcı birden fazla görüntü seçmiş olabilir. GetData'dan önce getClipData'nın işlenmesi , ancak her iki durumun da ele alınması , farklı cihazları desteklemek ve aynı zamanda birden fazla Uris'e izin vermek için önemlidir.
Mira_Cole

@Mira_Code Seçilen görüntüleri farklı görüntü görünümlerine nasıl ayarlayabilirim.
Hasnain Ghias

20

Umarım bu cevap geç değildir. Galeri widget'ı varsayılan olarak çoklu seçimi desteklemediğinden, ancak çoklu seçim amacınızı kabul eden ızgara görünümünü özelleştirebilirsiniz. Diğer seçenek, galeri görünümünü genişletmek ve çoklu seçime izin vermek için kendi kodunuzu eklemektir.
Bunu yapabilecek basit kitaplık şudur: https://github.com/luminousman/MultipleImagePick

Güncelleme :
@ ilsy yorumuna itibaren CustomGalleryActivity bu kütüphane kullanımında manageQuerybu şekilde değiştirilmelidir, böylece itiraz edildi, getContentResolver().query()ve cursor.close()benzeri bu cevap


@ R4j Evet ve bunun hakkında yazdım: kütüphane projelerde kullanılmaya hazır değil. Kullanmaya başlamak için birçok güncellemeye ihtiyacınız var. Ve güncellemeniz hakkında: getContentResolver().query()UI iş parçacığında kullanmayın . Yükleyiciler ve Destek Kitaplığı hakkında bilgi edinin.
mbelsky

.cacheOnDisc()ayrıca kullanımdan kaldırıldı, bu yüzden .cacheOnDisc(true)boole param ile değiştirin
Pratik Butani

5

Örneği başlatın:

private String imagePath;
private List<String> imagePathList;

In onActivityResult Bunu If-else 2 bloğunu yazmalısınız. Biri tek görüntü için, diğeri birden çok görüntü için.

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

En önemli kısım, Görüntü Yolunu uri'den Alın :

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

Umarım bu size yardımcı olabilir.


1

Öğesinden null aldım Cursor. Sonra dönüştürmek için bir çözüm bulduk Uriiçine Bitmapmükemmel olduğunu işler.

İşte benim için çalışan çözüm:

@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

Merhaba aşağıdaki kod iyi çalışıyor.

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

Daha fazla açıklama istiyorsun. http://mylearnandroid.blogspot.in/2014/02/multiple-choose-custom-gallery.html


1
işe yararsa sorun değil. Kullanımdan kaldırılmış kodu belirtmek iyidir, ancak herhangi bir sorun yaşamadan kullandığınız sürece kullanmakta bir sakınca yoktur. Neden kullanımdan kaldırıldığını, güvenlik sorunları olup olmadığını, daha yeni kodun daha verimli olduğunu vb. Bilmek önemlidir. Ancak Android uygulamaları ileriye dönük uyumlu olduğundan, kullanımdan kaldırılan kodlar gelecekte yine de çalışacaktır.
JStephen

0

Ben de aynı sorunu yaşadım. Kullanıcıların galeriden fotoğraf seçerken kolayca fotoğraf çekebilmesini de istedim. Bunu yapmanın yerel bir yolunu bulamadım, bu yüzden açık kaynak bir proje yapmaya karar verdim. MultipleImagePick'e çok benziyor, ancak onu uygulamanın daha iyi bir yolu.

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

Bunu bir IntentChooser deneyin . Sadece birkaç satır kod ekleyin, gerisini sizin için yaptım.

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

Not: yukarıdaki yanıtlarda belirtildiği gibi, EXTRA_ALLOW_MULTIPLE yalnızca API> = 18 için kullanılabilir. Ve bazı galeri uygulamaları bu özelliği kullanıma sunmaz (Google Fotoğraflar ve Belgeler ( com.android.documentsui) çalışır.


Eklenmiş olmasına rağmen birden fazla resim seçmeme izin vermiyorintent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Scorpion
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.