web-dev-qa-db-ja.com

ユーザーが写真を撮ることができる単一の目的ORギャラリーから画像を選択するAndroid

Android 2.1以上)向けのアプリを開発しています。ユーザーがアプリ内でプロフィール画像を選択できるようにしたい(連絡先フレームワークを使用していません)。

理想的な解決策は、ユーザーがギャラリーから画像を選択できるようにするインテントを起動することですが、適切な画像が利用できない場合は、カメラを使用して写真を撮影します(またはその逆、つまりユーザーが写真を撮影できるようにします)彼らはすでに適切な画像を既に持っていることを知っているので、ギャラリーにドロップしてその画像を選んでもらいます)。

現在、どちらか一方を実行できますが、両方は実行できません。

MediaStore.ACTION_IMAGE_CAPTUREを使用してカメラモードに直接移動する場合、ギャラリーにドロップするオプションはありません。

Intent.ACTION_PICKを使用してギャラリーに直接移動すると、画像を選択できますが、(ギャラリーの右上隅にある)カメラボタンをクリックすると、新しいカメラインテントが起動します。そのため、撮影された写真はアプリケーションに直接返されません。 (確かに戻るボタンを押してギャラリーに戻ってそこから画像を選択できますが、これは余分な不要なステップであり、まったく直感的ではありません)。

したがって、両方を組み合わせる方法はありますか、またはアプリケーション内からどちらか一方を実行するメニューを提供する必要がありますか?それは一般的なユースケースになるようです...確かに私は何かを見逃していますか?

66
Damian

[〜#〜] update [〜#〜]:他の回答、EXTRA_INITIAL_INTENTS、この時点でより良いものです。答えを書いたとき、EXTRA_INITIAL_INTENTSはAPIレベル5で追加されたため、まだ存在していませんでした。

したがって、両方を組み合わせる方法はありますか、またはアプリケーション内からどちらか一方を実行するメニューを提供する必要がありますか?

必要な機能を備えた独自のギャラリーを作成します。

メニューはもっとシンプルになると思います。

それは一般的なユースケースになるようです...確かに私は何かを見逃していますか?

隣の開発者は、ギャラリーでローカルギャラリーから選択するか、Flickrにアクセスして選択できるようにする必要があると考えます。別の開発者は、カメラがカメラを介して「写真を撮る」だけでなく、ギャラリーから何かを選択することで「写真を撮る」ことを許可するべきだと考えます。さらに別の開発者は、ギャラリーがローカルギャラリー、Flickr、カメラ、またはネットワークに接続されたWebカメラからの選択を許可する必要があると考えるでしょう。さらに別の開発者は、ギャラリーが愚かで、ユーザーがファイルエクスプローラーでファイルを選択するだけだと考えるでしょう。等々。

これはすべて、OSのフラッシュが貴重な環境(携帯電話)で行われます。

したがって、私見では、コアAndroidチームが、考えられるすべてのパターンに対応しようとするのではなく、適切と思われるように組み立てるためのビルディングブロックを提供することにしました。

13
CommonsWare

次のようなことを試してみることができます。

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

119
Macarse

アクティビティで次の手順を実行できます。

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();
            }
        }
    }
10
Dario Bruzzese

私の答えは@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")
        }
    }
}
2
vovahost