Единственное намерение позволить пользователю сделать снимок ИЛИ выбрать изображение из галереи в Android - PullRequest
66 голосов
/ 25 апреля 2010

Я разрабатываю приложение для Android 2.1 и выше. Я хочу, чтобы мои пользователи могли выбирать изображение профиля в моем приложении (я не использую структуру контактов).

Идеальным решением было бы создание намерения, позволяющего пользователю выбрать изображение из галереи, но если подходящее изображение недоступно, используйте камеру для съемки (или наоборот, т. Е. Разрешите пользователю делать снимок). изображение, но если они знают, что у них уже есть подходящее изображение, позвольте им зайти в галерею и выбрать указанное изображение).

В настоящее время я могу сделать одно или другое, но не оба.

Если я перехожу прямо в режим камеры с помощью MediaStore.ACTION_IMAGE_CAPTURE, то нет никакой возможности зайти в галерею.

Если я иду прямо в галерею с помощью Intent.ACTION_PICK, я могу выбрать изображение, но если я нажму кнопку камеры (в верхнем правом углу галереи), то будет запущено новое намерение камеры. Таким образом, любая сделанная фотография не возвращается непосредственно в мое приложение. (Конечно, вы можете нажать кнопку «Назад», чтобы вернуться в галерею и выбрать изображение оттуда, но это дополнительный ненужный шаг и совсем не интуитивный).

Так есть ли способ объединить оба или мне придется предложить меню, чтобы сделать то или другое из моего приложения? Похоже, это был бы общий случай использования ... конечно, я что-то упустил?

Ответы [ 4 ]

119 голосов
/ 26 июля 2012

Вы можете попробовать сделать что-то вроде этого:

// ...
// Within your enclosing Class
// ...
private static final int SELECT_PICTURE = 1;

// ... 

Intent pickIntent = new Intent();
pickIntent.setType("image/*");
pickIntent.setAction(Intent.ACTION_GET_CONTENT);

Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

String pickTitle = "Select or take a new Picture"; // Or get from strings.xml
Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
chooserIntent.putExtra
(
  Intent.EXTRA_INITIAL_INTENTS, 
  new Intent[] { takePhotoIntent }
);

startActivityForResult(chooserIntent, SELECT_PICTURE);

Чтобы узнать, как обработать результат деятельности, см. этот вопрос


Примечание: критический момент - как определить, использовалась ли камера или галерея. Это показано в этом примере кода: https://stackoverflow.com/a/12347567/294884

13 голосов
/ 25 апреля 2010

ОБНОВЛЕНИЕ : Другой ответ, использующий EXTRA_INITIAL_INTENTS, является лучшим на данный момент. На момент написания моего ответа EXTRA_INITIAL_INTENTS еще не существовало, поскольку оно было добавлено в API уровня 5.

Так есть ли способ объединить оба или я собираюсь предложить меню сделать один или другой из моего приложение?

Напишите свою собственную галерею, в которой есть нужные вам функции.

Я бы подумал, что меню будет проще.

Похоже, это будет обычное использование дело ... конечно я что-то упустил?

Разработчик, находящийся рядом с вами, подумает, что галерея должна позволить вам выбирать из локальной галереи, или же перейти на Flickr, чтобы сделать выбор оттуда. Другой разработчик подумает, что камера должна не только позволять «делать снимки» через камеру, но и «делать снимки», выбирая что-то из галереи, переворачивая вещи так, как вы себе это представляете. Еще один разработчик подумает, что галерея должна позволять выбирать из локальной галереи, или Flickr, или камеры, или веб-камеры, подключенной к сети. Еще один разработчик подумает, что галерея глупа, и пользователи должны просто выбирать файлы через проводник. И так далее.

Все это в среде (мобильные телефоны), где флеш для ОС стоит дороже.

Следовательно, ИМХО, не совсем шокирует, что основная команда Android решила предоставить вам строительные блоки для сборки по своему усмотрению, вместо того, чтобы пытаться приспособить все возможные шаблоны.

10 голосов
/ 11 сентября 2015

Вы можете продолжить в своей деятельности:

private static final int REQUEST_CODE_PICTURE= 1;

    /**
     * Click on View to change photo. Sets into View of your layout, android:onClick="clickOnPhoto"
     * @param view View
     */
    public void clickOnPhoto(View view) {
        Intent pickIntent = new Intent();
        pickIntent.setType("image/*");
        pickIntent.setAction(Intent.ACTION_GET_CONTENT);
        Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        String pickTitle = "Take or select a photo";
        Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { takePhotoIntent });
        startActivityForResult(chooserIntent, REQUEST_CODE_PICTURE);
    }

Затем всегда добавляйте в свою активность метод onActivityResult:

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_PICTURE && resultCode == Activity.RESULT_OK) {
            if (data == null) {
                return;
            }
            try {
                InputStream inputStream = getContentResolver().openInputStream(data.getData());
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                imgPhoto.setImageBitmap(bitmap);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
2 голосов
/ 16 марта 2018

Мой ответ почти идентичен решению @Macarse, но я также добавляю дополнительное намерение показывать приложения галереи (например, Google Photos) и написана на Kotlin:

val REQUEST_CODE_GET_IMAGE = 101

private fun addProfileImage() {
    val pickImageFileIntent = Intent()
    pickImageFileIntent.type = "image/*"
    pickImageFileIntent.action = Intent.ACTION_GET_CONTENT

    val pickGalleryImageIntent = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)

    val captureCameraImageIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

    val pickTitle = "Capture from camera or Select from gallery the Profile photo"
    val chooserIntent = Intent.createChooser(pickImageFileIntent, pickTitle)
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(captureCameraImageIntent, pickGalleryImageIntent))
    startActivityForResult(chooserIntent, REQUEST_CODE_GET_IMAGE)
}

Извлечение изображения из результата:

private var imageTempFile: File? = null
private var imageMimeType: String? = null

private fun extractImage(intent: Intent?) {
    val imageUri = intent?.data
    imageUri?.let {
        Glide.with(this)
                .load(imageUri)
                .into(profileImageCiv)
        imageTempFile = MediaUtils.copyContentFromUriToCacheFile(this, imageUri, Settings.DIRECTORY_CACHE_TEMP_PROFILE_IMAGE)
        imageMimeType = MediaUtils.getMimeType(this, imageUri)
    } ?: run {
        intent?.extras?.get("data")?.let { bitmap ->    // Bitmap was returned as raw bitmap
            Glide.with(this)
                    .load(bitmap)
                    .into(profileImageCiv)
            imageTempFile = MediaUtils.writeBitmapToCacheFile(this, bitmap as Bitmap, Settings.DIRECTORY_CACHE_TEMP_PROFILE_IMAGE)
            imageMimeType = "image/jpeg"    // The bitmap was compressed as JPEG format. The bitmap itself doesn't have any format associated to it
        } ?: run {
            imageTempFile = null
            imageMimeType = null
            Log.e("Intent data is null.")
            Log.d("Error during photo selection")
        }
    }
}
...