Wybierz wiele obrazów z galerii Androida

114

Więc w zasadzie to, co próbuję osiągnąć, to otworzyć Galleryw systemie Android i pozwolić użytkownikowi wybrać multiple images. Teraz to pytanie jest zadawane często, ale nie jestem zadowolony z odpowiedzi. Głównie dlatego, że znalazłem coś interesującego w de docs w moim IDE (wrócę do tego później) i dlatego nie chcę używać niestandardowego adaptera, ale tylko waniliowego.

Teraz mój kod do wyboru jednego obrazu to:

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

Teraz ludzie w SO i innych witrynach powiedzą Ci, że masz dwie opcje:

1) Nie używaj, ACTION_GET_CONTENTale ACTION_SEND_MULTIPLEzamiast tego.
Ten nie działa. Ten jest zgodny z dokumentacją dotyczącą sendingplików, a nie, retrievingi dokładnie to robi. Podczas korzystania z ACTION_SEND_MULTIPLE otworzyło się okno na moim urządzeniu, w którym muszę wybrać aplikację, do której mam wysłać moje dane. Nie tego chcę, więc zastanawiam się, jak ludzie osiągnęli to dzięki temu rozwiązaniu. Czy coś mi brakuje?

2) Zaimplementuj custom Gallery. To moja ostatnia opcja, którą rozważę, ponieważ nie jest to, czego szukam, ponieważ muszę sam ją stylizować I dlaczego do cholery po prostu nie możesz wybrać wielu zdjęć w galerii waniliowej?

Musi istnieć opcja na to .. Teraz interesująca rzecz, którą znalazłem, jest taka:
znalazłem to w opisie docs ACTION_GET_CONTENT.

Jeśli wywołujący może obsłużyć wiele zwracanych elementów (użytkownik dokonujący wielokrotnego wyboru), może określić EXTRA_ALLOW_MULTIPLE, aby to wskazać.

To jest całkiem interesujące. Tutaj odnoszą się do przypadku użycia, w którym użytkownik może wybrać wiele elementów?

Później w dokumentach mówią:

Możesz użyć EXTRA_ALLOW_MULTIPLE, aby umożliwić użytkownikowi wybranie wielu elementów.

Więc to jest całkiem oczywiste, prawda? To jest to, czego potrzebuję. Ale moje następujące pytanie brzmi: gdzie mogę to umieścić EXTRA_ALLOW_MULTIPLE? Smutne jest to, że nie mogę znaleźć tego nigdzie w podręczniku programistów.android, a także nie jest to zdefiniowane jako stała w klasie INTENT.

Czy ktoś może mi w tym pomóc EXTRA_ALLOW_MULTIPLE?

Dion Segijn
źródło
1
Rozwiązanie @KyleShank zadziałało dla mnie. Ustawienie EXTRA_ALLOW_MULTIPLEpozwala wybrać wiele elementów. Uzyskaj identyfikatory URI, wywołując getClipData()zwróconą intencję w onActivityResult. Jedynym problemem jest to, że widżet galerii nie pozwala na wielokrotny wybór. W takim przypadku kliknięcie dowolnego obrazu zakończy wybór i możesz uzyskać identyfikator URI (pojedynczego elementu), wywołując getDatazwróconą intencję
Tanweer Alam

Odpowiedzi:

122

Opcja EXTRA_ALLOW_MULTIPLE jest ustawiana na intencji za pomocą metody Intent.putExtra ():

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

Twój kod powyżej powinien wyglądać następująco:

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

Uwaga: ta EXTRA_ALLOW_MULTIPLEopcja jest dostępna tylko w Android API 18 i nowszych.

Kyle Shank
źródło
Wiem o tym, ale jak wspomniałem w mojej odpowiedzi: „Smutne jest to, że nie mogę znaleźć tego nigdzie w przewodniku dla programistów.android, a także nie jest to zdefiniowane jako stała w klasie INTENT”. Moje IDE nie rozpoznaje Intent.EXTRA_ALLOW_MULTIPLE. Mam zainstalowane API na poziomie 18. Moje IDE mówi: „EXTRA_ALLOW_MULTIPLE nie może zostać rozwiązane lub nie jest polem”
Dion Segijn
intent.putExtra (Intent.EXTRA_ALLOW_MULTIPLE, true); użyj emulatora, nie obsługuj wielokrotnego wyboru.
qinmiao
11
Jego wybór wielu obrazów. ale jak uzyskać adres URL obrazu z wyniku działania ????
John
4
To uruchamia selektor obrazów i pozwala mi wybrać wiele obrazów, ale nie wiem, jak uzyskać adresy URL w onActivityResult.
Tom Kincaid
5
Możesz uzyskać adresy URL w wyniku Intent.getClipData. Posiada tablicę ClipData Item.
Tam Huynh
71

Zdefiniuj te zmienne w klasie:

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

Załóżmy, że onClick na przycisku powinien otworzyć galerię, aby wybrać obrazy

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

Następnie należy zastąpić metodę 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);
}

PAMIĘTAJ, ŻE: galeria nie daje możliwości wyboru wielu obrazów, dlatego otwieramy tutaj wszystkie studio obrazów, z których można wybrać wiele obrazów. i nie zapomnij dodać uprawnień do swojego manifestu

BARDZO WAŻNE: getData (); aby uzyskać jeden obraz i zapisałem go tutaj w imageEncoded String jeśli użytkownik wybierze wiele obrazów, powinny one być zapisane na liście

Musisz więc sprawdzić, który jest pusty, aby użyć drugiego

Życzę miłej próby i innym

Laith Mihyar
źródło
Pominąłem "intent.setType (" image / * ");" i wysyła użytkowników bezpośrednio do Photo zamiast dać użytkownikowi szansę na przejście do Galerii, która nie pozwala na wybór wielu zdjęć. Nie jestem pewien, czy to z tego powodu, moja metoda getData () nigdy nie zwraca wartości null, więc ostatecznie użyłem getClipData wyłącznie do wyboru pojedynczego i wielokrotnego obrazu.
Johnny Wu
1
wystarczy użyć części data.getClipData (), nie ma potrzeby sprawdzania danych.getData ()
truongnm
&& null! = dane ??
Odaym
8
Uri uri = content: //com.android.providers.media.documents/document/image%3A772 uri ma dane, ale kursor.getString zwraca do mnie wartość null imageEncoded = cursor.getString (columnIndex);
Muhammad Zubair Ashraf
2
Było to przydatne, ale musiałem uzupełnić te funkcje dla getPath: stackoverflow.com/a/20559175/6141959
Geynen
31

Wiele z tych odpowiedzi ma podobieństwa, ale we wszystkich brakuje najważniejszej części, która jest dostępna. Przed sprawdzeniem onActivityResultsprawdź, czy data.getClipDatajest pustadata.getData

Kod wywołujący wybór plików:

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

Kod umożliwiający pobranie wszystkich wybranych obrazów:

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

Pamiętaj, że na niektórych urządzeniach w selektorze Androida są dostępne Zdjęcia i Galeria. Zdjęcia umożliwia wybranie wielu obrazów. Galeria umożliwia tylko jedną naraz.

Mira_Cole
źródło
co to jest getClipData ()? czy data.getData nie jest wystarczająca?
adi
1
W przypadku niektórych urządzeń Samsung wyniki będą inne niż w przypadku urządzeń innych firm. Jeśli użytkownik wybierze wiele plików, getData()czasami NIE będzie miał wartości NULL, ale będzie miał tylko jeden Uri. Jeśli chcesz poradzić sobie z sytuacją, gdy użytkownik wybierze wiele plików, sprawdź getClipData()wcześniej getData()- jeśli dane klipu nie są puste, użytkownik mógł wybrać wiele obrazów. Obsługa getClipData przed getData, ale obsługa obu przypadków jest ważna dla obsługi różnych urządzeń, przy jednoczesnym umożliwieniu wielu Uris.
Mira_Cole
@Mira_Code Jak mogę ustawić wybrane obrazy na różne widoki obrazów.
Hasnain Ghias
20

Mam nadzieję, że ta odpowiedź nie jest spóźniona. Ponieważ widżet galerii nie obsługuje domyślnie wielokrotnego wyboru, ale możesz dostosować widok siatki, który zaakceptował Twój zamiar wielokrotnego wyboru. Inną opcją jest rozszerzenie widoku galerii i dodanie własnego kodu, aby umożliwić wielokrotny wybór.
Oto prosta biblioteka, która może to zrobić: https://github.com/luminousman/MultipleImagePick

Aktualizacja :
Z komentarza @ ilsy, CustomGalleryActivity w tej bibliotece używa manageQuery, która jest przestarzała, więc należy ją zmienić na tę odpowiedźgetContentResolver().query() i cursor.close()polubić

R4j
źródło
@ R4j Tak i pisałem o tym: biblioteka nie jest gotowa do wykorzystania w projektach. Potrzebujesz wielu aktualizacji, aby zacząć z niego korzystać. A co do twojej aktualizacji: nie używaj getContentResolver().query()w wątku interfejsu użytkownika. Przeczytaj o programach ładujących i bibliotece wsparcia.
mbelsky
.cacheOnDisc()również przestarzałe, więc zmień je na .cacheOnDisc(true)parametr boolean
Pratik Butani
5

Zainicjuj instancję:

private String imagePath;
private List<String> imagePathList;

W onActivityResult musisz napisać to, jeśli-else 2 blok. Jeden dla pojedynczego obrazu, a drugi dla wielu obrazów.

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

Najważniejsza część, Pobierz ścieżkę obrazu z 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();
    }
}

Mam nadzieję, że to może ci pomóc.

Hasib Akter
źródło
1

Mam null z Cursor. Następnie znalazłem rozwiązanie, które pozwoli przekształcić plik Uriw, Bitmapktóre działa idealnie.

Oto rozwiązanie, które działa dla mnie:

@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
źródło
0

Cześć, poniższy kod działa dobrze.

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

Chcesz więcej wyjaśnień. http://mylearnandroid.blogspot.in/2014/02/multiple-choose-custom-gallery.html

Ramesh Thangaraj
źródło
1
jeśli to działa, to dobrze. Dobrze jest wskazać przestarzały kod, ale jeśli używasz go bez żadnych problemów, można go używać. Ważne jest, aby wiedzieć, dlaczego jest przestarzały, czy są to problemy z bezpieczeństwem, nowszy kod jest bardziej wydajny itp. Ale ponieważ aplikacje na Androida są kompatybilne z nowszymi wersjami, przestarzały kod będzie nadal działał w przyszłości.
JStephen
0

Miałem też ten sam problem. Zależało mi również na tym, aby użytkownicy mogli łatwo robić zdjęcia podczas wybierania zdjęć z galerii. Nie mogłem znaleźć natywnego sposobu na zrobienie tego, dlatego zdecydowałem się stworzyć projekt open source. To jest bardzo podobne do MultipleImagePick, ale po prostu lepszy sposób jego implementacji.

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
źródło
0

Wypróbuj ten IntentChooser . Po prostu dodaj kilka linii kodu, resztę zrobiłem za Ciebie.

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: jak wspomniano w odpowiedziach powyżej, EXTRA_ALLOW_MULTIPLE jest dostępne tylko dla API> = 18. Niektóre aplikacje galerii nie udostępniają tej funkcji (Zdjęcia i Dokumenty Google ( com.android.documentsui)).

Tuan Chau
źródło
Nie pozwalając mi wybrać wielu zdjęć, mimo że dodanointent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Scorpion