写真を新しく撮るか、ギャラリから取得するか選択する方法

アプリケーションから写真を利用する方法としては、当然ながら、新しく写真を撮影するか、既に存在する写真を利用するか、二通りあります。

アンドロイド端末のカメラを使って写真を撮影して、それを利用する方法については、 カメラの利用 で説明しました。

また、既に存在する写真を利用する方法としては、ギャラリから写真を選ぶというのが便利です。

例えばツイッターなどで、ツイートに写真を挿入する場合は次のスクリーンショットのように、ギャラリから写真を選ぶボタンと、 カメラで写真を撮るというボタンが個別に用意されています。

ツイッターの画像挿入方法

これはこれで、わかりやすい良い方法です。

しかしながら、次のようにインテントの選択ダイアログ (IntentChooser) に写真を選択するか、カメラから写真を選択 (即ち写真を撮る) するか、 選ぶというのも直感的にわかりやすい方法といえます。

インテント選択ダイアログ

どちらが良いかというのはここでは横においておいて、ここでは技術的に、こうした複数の異なる種類のインテントを選択させるダイアログをどのように実装するか説明します。

ここで作るプログラムでは次のようになります。

プログラムが起動し・・・

メニューから "Set Image" を選択します。

すると、「写真を撮る」というインテントと「写真を選択する」というインテントを処理するプログラムが表示されます。

カメラを選択すると、カメラが起動して写真を撮影し・・・

それを OK (チェックマークをタップ) すると・・・

プログラム内の画面 (ImageView) にそれがセットされます。

また、選択ダイアログ (インテントチューザー) でギャラリを選択すると・・・

ギャラリから写真が選べるようになり・・・

選択された写真がプログラム内に表示されます。

これを実装するコードは次のようになります。(レイアウトは ImageView をリニアレイアウト内にひとつ置いただけのものなのでここでは省略します)

package com.example.multiintenttest1;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.provider.MediaStore;

public class MainActivity extends Activity {

  static final int REQUEST_GET_IMAGE = 100;

  ImageView imageView1;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    imageView1 = (ImageView)findViewById(R.id.imageView1);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    if (id == R.id.action_set_image) {
      Intent pickPhotoIntent = new Intent(
        Intent.ACTION_GET_CONTENT);
      pickPhotoIntent.setType("image/*");

      Intent takePhotoIntent = new Intent(
        MediaStore.ACTION_IMAGE_CAPTURE);

      Intent chooserIntent = Intent.createChooser(
        pickPhotoIntent, "Picture...");
      chooserIntent.putExtra(
        Intent.EXTRA_INITIAL_INTENTS,
        new Intent[]{takePhotoIntent});

      startActivityForResult(
        chooserIntent,
        REQUEST_GET_IMAGE);
      return true;
    }
    return super.onOptionsItemSelected(item);
  }

  @Override
  protected void onActivityResult(
    int requestCode,
    int resultCode,
    Intent data) {
    if(REQUEST_GET_IMAGE == requestCode
      resultCode == Activity.RESULT_OK
      data != null){

      try {
        if(data.getExtras() != null
          data.getExtras().get("data")!= null){
          Bitmap capturedImage
            = (Bitmap) data.getExtras().get("data");
          imageView1.setImageBitmap(capturedImage);
        }
        else{
          InputStream stream
            = getContentResolver().openInputStream(
              data.getData());
          Bitmap bitmap =
              BitmapFactory.decodeStream(stream);
          stream.close();
          imageView1.setImageBitmap(bitmap);
        }
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

  }
}

ポイントは次の箇所です。

  public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    if (id == R.id.action_set_image) {
      // インテントを二つ作成
      Intent pickPhotoIntent = new Intent(
        Intent.ACTION_GET_CONTENT);
      pickPhotoIntent.setType("image/*");

      Intent takePhotoIntent = new Intent(
        MediaStore.ACTION_IMAGE_CAPTURE);

      // チューザーの作成
      Intent chooserIntent = Intent.createChooser(
        pickPhotoIntent, "Picture...");
      chooserIntent.putExtra(
        Intent.EXTRA_INITIAL_INTENTS,
        new Intent[]{takePhotoIntent});

      startActivityForResult(
        chooserIntent,
        REQUEST_GET_IMAGE);

チューザーにエクストラインテント (Extra Intents = 追加のインテント) として、インテントの配列を渡しています。

これによりチューザー内に追加のインテントとして指定したものも含めたリストが表示されます。

onActivityResult では、インテントを処理した方法によってビットマップの作成方法が異なるので、データの作成方法が分岐しています。

こうした複雑さを導入しないためには、前述のツイッター方式を選択すべきといえますが、画像をセットしたい、というハイレベルな意図を満たすには、 同じ選択画面にその意図を満たすプログラムが列挙されているというのも魅力的ともいえますね。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Android 開発入門