66

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

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

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

如果我使用 MediaStore.ACTION_IMAGE_CAPTURE 直接进入相机模式,则没有选项可以放入图库。

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

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

4

4 回答 4

120

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

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

于 2012-07-26T19:20:37.427 回答
13

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

那么有没有办法将两者结合起来,或者我是否必须提供一个菜单来从我的应用程序中执行其中一个或另一个?

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

我认为菜单会更简单。

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

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

所有这些都是在操作系统闪存非常重要的环境(手机)中进行的。

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

于 2010-04-25T13:35:21.023 回答
10

您可以在 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);
    }

然后,始终在您的 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();
            }
        }
    }
于 2015-09-11T09:03:24.217 回答
3

我的答案与@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)
}

从结果意图中提取图像:

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")
        }
    }
}
于 2018-03-15T23:02:05.943 回答