单一意图让用户拍照或从 Android 中的图库中选择图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2708128/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:01:59  来源:igfitidea点击:

Single intent to let user take picture OR pick image from gallery in Android

androidimagecameraandroid-intentgallery

提问by Damian

I'm developing an app for Android 2.1 upwards. I want to enable my users to select a profile picture within my app (I'm not using the contacts framework).

我正在为 Android 2.1 以上开发应用程序。我想让我的用户在我的应用程序中选择个人资料图片(我没有使用联系人框架)。

The ideal solution would be to fire an intent that enables the user to select an image from the gallery, but if an appropriate image is not available then use the camera to take a picture (or vice-versa i.e. allow user to take picture but if they know they already have a suitable image already, let them drop into the gallery and pick said image).

理想的解决方案是触发一个意图,使用户能够从图库中选择图像,但如果没有合适的图像,则使用相机拍照(反之亦然,即允许用户拍照,但如果他们知道他们已经有了合适的图像,让他们进入画廊并选择所述图像)。

Currently I can do one or the other but not both.

目前我可以做一个或另一个,但不能同时做。

If I go directly into camera mode using MediaStore.ACTION_IMAGE_CAPTURE then there is no option to drop into the gallery.

如果我使用 MediaStore.ACTION_IMAGE_CAPTURE 直接进入相机模式,则无法进入图库。

If I go directly to the gallery using Intent.ACTION_PICK then I can pick an image but if I click the camera button (in top right hand corner of gallery) then a new camera intent is fired. So, any picture that is taken is not returned directly to my application. (Sure you can press the back button to drop back into the gallery and select image from there but this is an extra unnecessary step and is not at all intuitive).

如果我使用 Intent.ACTION_PICK 直接进入画廊,那么我可以选择一个图像,但如果我单击相机按钮(在画廊的右上角),则会触发一个新的相机意图。因此,拍摄的任何照片都不会直接返回到我的应用程序。(当然你可以按后退按钮回到图库并从那里选择图像,但这是一个额外的不必要的步骤,一点也不直观)。

So is there a way to combine both or am I going to have to offer a menu to do one or the other from within my application? Seems like it would be a common use case...surely I'm missing something?

那么有没有办法将两者结合起来,或者我将不得不提供一个菜单来从我的应用程序中做一个或另一个?似乎这将是一个常见的用例......我肯定错过了什么吗?

采纳答案by CommonsWare

UPDATE: The other answer, using EXTRA_INITIAL_INTENTS, is a better one at this point. At the time I wrote my answer, EXTRA_INITIAL_INTENTSdid not yet exist, as it was added in API Level 5.

更新EXTRA_INITIAL_INTENTS在这一点上,使用 的另一个答案是更好的答案。在我写我的答案时,EXTRA_INITIAL_INTENTS还不存在,因为它是在 API 级别 5 中添加的。

So is there a way to combine both or am I going to have to offer a menu to do one or the other from within my application?

那么有没有办法将两者结合起来,或者我将不得不提供一个菜单来从我的应用程序中做一个或另一个?

Write your own gallery that has the features you desire.

编写您自己的具有您想要的功能的画廊。

I would think a menu would be simpler.

我认为菜单会更简单。

Seems like it would be a common use case...surely I'm missing something?

似乎这将是一个常见的用例......我肯定错过了什么吗?

The developer next to you will think the gallery should allow you to pick from the local gallery or else hop out to Flickr to make a selection from there. Another developer will think the camera should not only allow to "take a picture" via the camera but to "take a picture" via choosing something from the gallery, inverting things from the way you envision it. Yet another developer will think that the gallery should allow picking from the local gallery, or Flickr, or the camera, or a network-attached webcam. Still another developer will think that the gallery is stupid and users should just pick files via a file explorer. And so on.

您旁边的开发人员会认为画廊应该允许您从当地画廊中挑选,或者跳出 Flickr 从那里进行选择。另一位开发人员会认为相机不仅应该允许通过相机“拍照”,还应该通过从画廊中选择一些东西来“拍照”,从你想象的方式反转事物。另一个开发人员会认为画廊应该允许从本地画廊、Flickr、相机或网络连接的网络摄像头中挑选。还有一个开发人员会认为图库是愚蠢的,用户应该通过文件浏览器选择文件。等等。

All of this in an environment (mobile phones) where flash for the OS is at a premium.

所有这一切都发生在操作系统闪存非常宝贵的环境(手机)中。

Hence, IMHO, it is not completely shocking that the core Android team elected to provide building blocks for you to assemble as you see fit, rather than trying to accommodate every possible pattern.

因此,恕我直言,核心 Android 团队选择提供构建块供您按照您认为合适的方式进行组装,而不是试图适应所有可能的模式,这并不完全令人震惊。

回答by Macarse

You can try doing something like this:

你可以尝试做这样的事情:

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

To see how to handle the activitiy's result, please refer to this question

要查看如何处理活动的结果,请参阅此问题



Note: a critical point is how to determine whether the camera or gallery was used. That is shown in this code example: https://stackoverflow.com/a/12347567/294884

注意:一个关键点是如何确定是否使用了相机或图库。在此代码示例中显示:https: //stackoverflow.com/a/12347567/294884

回答by Dario Brux

You can proceed in this way in your Activity:

您可以在您的活动中以这种方式进行:

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

Then, add always in your Activity the method onActivityResult:

然后,始终在您的 Activity 中添加 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();
            }
        }
    }

回答by vovahost

My Answer is almost identical to @Macarse solution but I also add an additional intent to show gallery apps (Ex: Google Photos) and is written in Kotlin:

我的答案几乎与@Macarse 解决方案相同,但我还添加了一个额外的意图来显示图库应用程序(例如:Google 相册)并且是用 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)
}

Extract image from result intent:

从结果意图中提取图像:

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