Sélectionnez plusieurs images de la galerie Android

114

Donc, fondamentalement, ce que j'essaie de réaliser, c'est d'ouvrir le Gallerysous Android et de laisser l'utilisateur sélectionner multiple images. Maintenant, cette question a été posée fréquemment mais je ne suis pas satisfait des réponses. Principalement parce que j'ai trouvé quelque chose d'intéressant dans de docs dans mon IDE (j'y reviendrai plus tard) et que je ne veux donc pas utiliser d'adaptateur personnalisé mais juste celui de la vanille.

Maintenant, mon code pour sélectionner une image est:

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

Maintenant, les gens sur SO et d'autres sites Web vous diront que vous avez 2 options:

1) Ne pas utiliser ACTION_GET_CONTENTmais à la ACTION_SEND_MULTIPLEplace.
Celui-ci ne fonctionne pas. Celui-ci est conforme à la documentation pour les sendingfichiers et non retrievinget c'est exactement ce qu'il fait. Lorsque j'utilise ACTION_SEND_MULTIPLE, une fenêtre s'ouvre sur mon appareil et je dois sélectionner une application à laquelle envoyer mes données. Ce n'est pas ce que je veux, alors je me demande comment les gens ont réalisé cela avec cette solution. Est-ce que je rate quelque chose?

2) Implémentez un custom Gallery. Maintenant, c'est ma dernière option que je vais envisager car à mon humble avis, ce n'est pas ce que je recherche car je dois le coiffer moi-même ET pourquoi diable vous ne pouvez tout simplement pas sélectionner plusieurs images dans la galerie vanille?

Il doit y avoir une option pour cela. Maintenant, la chose intéressante que j'ai trouvée est la suivante:
j'ai trouvé cela dans la description de la documentation ACTION_GET_CONTENT.

Si l'appelant peut gérer plusieurs éléments retournés (l'utilisateur effectuant une sélection multiple), il peut alors spécifier EXTRA_ALLOW_MULTIPLE pour l'indiquer.

C'est assez intéressant. Ici, ils font référence au cas d'utilisation où un utilisateur peut sélectionner plusieurs éléments?

Plus tard, ils disent dans la documentation:

Vous pouvez utiliser EXTRA_ALLOW_MULTIPLE pour permettre à l'utilisateur de sélectionner plusieurs éléments.

C'est donc assez évident, non? C'est de quoi j'ai besoin. Mais ma question suivante est: où puis-je mettre cela EXTRA_ALLOW_MULTIPLE? Le plus triste est que je ne trouve pas cela nulle part dans le guide developer.android et que cela n'est pas non plus défini comme une constante dans la classe INTENT.

Quelqu'un peut-il m'aider avec ça EXTRA_ALLOW_MULTIPLE?

Dion Segijn
la source
1
La solution @KyleShank a fonctionné pour moi. Le paramètre EXTRA_ALLOW_MULTIPLEvous permet de sélectionner plusieurs éléments. Obtenez les URI en appelant l' getClipData()intention renvoyée dans onActivityResult. Le seul problème est que le widget de la galerie ne permet pas la sélection multiple. Dans ce cas, cliquer sur n'importe quelle image terminera le choix et vous pourrez obtenir l'URI (d'un seul élément) en appelant l' getDataintention renvoyée
Tanweer Alam

Réponses:

122

L'option EXTRA_ALLOW_MULTIPLE est définie sur l'intention via la méthode Intent.putExtra ():

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

Votre code ci-dessus devrait ressembler à ceci:

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

Remarque: l' EXTRA_ALLOW_MULTIPLEoption n'est disponible que dans l'API Android 18 et versions ultérieures.

Kyle Shank
la source
Je le sais, mais comme je le mentionne dans ma réponse: "Le plus triste est que je ne trouve pas ce no where dans le guide developer.android et ce n'est pas non plus défini comme une constante dans la classe INTENT." Mon IDE ne reconnaît pas Intent.EXTRA_ALLOW_MULTIPLE. J'ai installé l'API niveau 18. Mon IDE dit: "EXTRA_ALLOW_MULTIPLE ne peut pas être résolu ou n'est pas un champ"
Dion Segijn
intent.putExtra (Intent.EXTRA_ALLOW_MULTIPLE, vrai); utiliser l'émulateur, ne prend pas en charge la sélection multiple.
qinmiao
11
Il sélectionne l'image multiple. mais comment obtenir l'url de l'image à partir du résultat d'activité ????
John
4
Cela lance le sélecteur d'images et me permet de sélectionner plusieurs images, mais je ne sais pas comment obtenir les URL dans onActivityResult.
Tom Kincaid
5
Vous pouvez obtenir les URL dans le résultat Intent.getClipData. Il a le tableau de ClipData Item.
Tam Huynh
71

Définissez ces variables dans la classe:

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

Supposons qu'en cliquant sur un bouton, il devrait ouvrir la galerie pour sélectionner des images

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

Ensuite, vous devez remplacer la méthode 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);
}

NOTEZ QUE: la galerie ne vous donne pas la possibilité de sélectionner plusieurs images, nous ouvrons donc ici tous les studios d'images que vous pouvez sélectionner multi-images à partir d'elles. et n'oubliez pas d'ajouter les autorisations à votre manifeste

TRÈS IMPORTANT: getData (); pour obtenir une seule image et je l'ai stockée ici dans imageEncoded String si l'utilisateur sélectionne plusieurs images, elles doivent être stockées dans la liste

Il faut donc vérifier laquelle est nulle pour utiliser l'autre

Je vous souhaite un bon essai et aux autres

Laith Mihyar
la source
J'ai sauté le "intent.setType (" image / * ");" et il envoie les utilisateurs directement à Photo au lieu de donner à l'utilisateur une chance d'aller à la Galerie qui ne permet pas la sélection multi-photos. Je ne sais pas si c'est à cause de cela, mon getData () ne renvoie jamais null, donc j'ai fini par utiliser getClipData exclusivement pour la sélection d'images simples et multiples.
Johnny Wu
1
il suffit d'utiliser la partie data.getClipData () est suffisant, pas besoin de vérifier data.getData ()
truongnm
&& null! = données ??
Odaym
8
Uri uri = content: //com.android.providers.media.documents/document/image%3A772 uri contient des données mais cursor.getString renvoie null pour moi imageEncoded = cursor.getString (columnIndex);
Muhammad Zubair Ashraf
2
C'était utile, mais je devais compléter avec ces fonctions pour le getPath: stackoverflow.com/a/20559175/6141959
Geynen
31

Beaucoup de ces réponses ont des similitudes mais il manque toutes la partie la plus importante qui se trouve onActivityResult, vérifiez si data.getClipDataest nul avant de vérifierdata.getData

Le code pour appeler le sélecteur de fichiers:

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

Le code pour obtenir toutes les images sélectionnées:

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

Notez que le sélecteur d'Android a des photos et une galerie disponibles sur certains appareils. Photos permet de sélectionner plusieurs images. La galerie n'en autorise qu'un à la fois.

Mira_Cole
la source
qu'est-ce que getClipData ()? data.getData n'est-il pas suffisant?
adi
1
Sur certains appareils Samsung, les résultats seront différents de ceux des appareils non Samsung. Si l'utilisateur sélectionne plusieurs fichiers, il getData()ne sera parfois PAS nul mais n'aura qu'un seul Uri. Si vous souhaitez gérer lorsqu'un utilisateur sélectionne plusieurs fichiers, vérifiez getClipData()avant getData()- si les données de clip ne sont pas nulles, l'utilisateur peut avoir sélectionné plusieurs images. Gérer getClipData avant getData, mais gérer les deux cas est important pour prendre en charge différents appareils tout en autorisant plusieurs Uris.
Mira_Cole
@Mira_Code Comment puis-je définir les images sélectionnées sur différentes vues d'image.
Hasnain Ghias le
20

J'espère que cette réponse n'est pas en retard. Parce que le widget de galerie ne prend pas en charge la sélection multiple par défaut, mais vous pouvez personnaliser la vue en grille qui a accepté votre intention de sélection multiple. L'autre option consiste à étendre la vue de la galerie et à ajouter votre propre code pour permettre une sélection multiple.
C'est la bibliothèque simple qui peut le faire: https://github.com/luminousman/MultipleImagePick

Mise à jour : à
partir du commentaire de @ ilsy, CustomGalleryActivity dans cette bibliothèque utilise manageQuery, qui est obsolète, elle devrait donc être remplacée par getContentResolver().query()et cursor.close()comme cette réponse

R4j
la source
@ R4j Oui et j'ai écrit à ce sujet: la bibliothèque n'est pas prête à être utilisée dans des projets. Besoin de nombreuses mises à jour pour commencer à l'utiliser. Et à propos de votre mise à jour: ne pas utiliser getContentResolver().query()dans le fil de l'interface utilisateur. En savoir plus sur les chargeurs et la bibliothèque de support.
mbelsky
.cacheOnDisc()également obsolète, alors changez-le en .cacheOnDisc(true)avec un
paramètre
5

Initialiser l'instance:

private String imagePath;
private List<String> imagePathList;

Dans onActivityResult Vous devez écrire ce bloc If-else 2. Un pour une seule image et un autre pour plusieurs images.

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

La partie la plus importante, obtenir le chemin de l'image depuis 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();
    }
}

J'espère que cela peut vous aider.

Hasib Akter
la source
1

Je suis nul du Cursor. Puis trouvé une solution pour convertir le Urien Bitmapqui fonctionne parfaitement.

Voici la solution qui fonctionne pour moi:

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

                        }
                    }

                }

            }

        }

    }

}
Sudarshan
la source
0

Salut le code ci-dessous fonctionne bien.

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

Vous souhaitez plus de précisions. http://mylearnandroid.blogspot.in/2014/02/multiple-choose-custom-gallery.html

Ramesh Thangaraj
la source
1
si ça marche, ça va. Il est bon de signaler le code obsolète, mais tant que vous l'utilisez sans aucun problème, son utilisation est correcte. Il est important de savoir pourquoi il est obsolète, s'il s'agit de problèmes de sécurité, un code plus récent est plus efficace, etc. Mais comme les applications Android sont compatibles avec les versions ultérieures, le code obsolète fonctionnera toujours à l'avenir.
JStephen
0

J'ai également eu le même problème. Je voulais également que les utilisateurs puissent prendre des photos facilement tout en sélectionnant des photos dans la galerie. Impossible de trouver un moyen natif de le faire, j'ai donc décidé de créer un projet open source. C'est un peu comme MultipleImagePick mais c'est juste une meilleure façon de l'implémenter.

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;
    }
}
Gil Julio
la source
0

Essayez celui-ci IntentChooser . Ajoutez simplement quelques lignes de code, j'ai fait le reste pour vous.

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

PS: comme mentionné dans les réponses ci-dessus, EXTRA_ALLOW_MULTIPLE n'est disponible que pour l'API> = 18. Et certaines applications de galerie ne rendent pas cette fonctionnalité disponible (Google Photos et Documents ( com.android.documentsui) fonctionnent.

Tuan Chau
la source
Ne pas me laisser choisir plusieurs images même si elles ont été ajoutéesintent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Scorpion