埋め込み写真選択ツール

連続した写真選択ツールの選択プロセスを示すアニメーション

埋め込みの写真選択ツールは、写真選択エクスペリエンスの別の形式であり、アプリのユーザー インターフェース内で直接操作できます。従来のフォト選択ツールと比較して、統合とカスタマイズのオプションが強化されています。setChildSurfacePackage メソッドを使用して SurfaceView にレンダリングされるため、埋め込みでないバージョンと同じセキュリティ機能とプライバシー機能が維持されます。

埋め込みの写真選択ツールを使用すると、ユーザーはクライアント アプリのフォーカスを失うことなく、デバイスとクラウドの写真ライブラリの両方から写真や動画を継続的に選択できます。クライアント アプリはアクティブなままで、そのアクティビティは再開状態にあり、ユーザーの選択にリアルタイムで応答できます。

埋め込みの写真選択ツールは、よりシームレスな UI 統合を提供しますが、特別な SurfaceView でレンダリングされるため、標準の写真選択ツールと同じセキュリティ機能とプライバシー機能を維持します。

利用可能なデバイス

埋め込み型の写真選択ツールは、Android 14(API レベル 34)と SDK 拡張機能バージョン 15 以降を搭載したデバイスでサポートされています。

これらの機能を備えていないデバイスは、Google Play 開発者サービスを使用して、従来の写真選択ツールまたはバックポート バージョンを利用できます。

Jetpack ライブラリの依存関係

Jetpack 写真選択ツール ライブラリを依存関係として追加します。

// For apps using Jetpack Compose
implementation("androidx.photopicker:photopicker-compose:1.0.0-alpha01")

// For apps using Views
implementation("androidx.photopicker:photopicker:1.0.0-alpha01")

埋め込みの写真選択ツールは、Jetpack Compose(推奨)または View を使用して統合できます。

Jetpack Compose の統合

EmbeddedPhotoPicker コンポーズ可能な関数は、埋め込みの写真選択ツール UI を Jetpack Compose 画面に直接含めるメカニズムを提供します。このコンポーザブルは、埋め込みの写真選択ツール UI をホストする SurfaceView を作成します。EmbeddedPhotoPicker サービスへの接続を管理し、ユーザー操作を処理して、選択されたメディア URI を呼び出し元アプリに伝えます。その際、必要なパラメータはわずかです。

val coroutineScope = rememberCoroutineScope()
val pickerState = rememberEmbeddedPhotoPickerState()

EmbeddedPhotoPicker(
    state = pickerState,
    onUriPermissionGranted = { uris ->
        _attachments.value += uris
    },
    onUriPermissionRevoked = { uris ->
        _attachments.value -= uris
    },
    onSelectionComplete = {
        // Hide the embedded photo picker as the user is done with the
        // photo/video selection
    },
)

連続選択

連続した写真選択ツールの選択プロセスを示すアニメーション

埋め込みの写真選択ツールを使用すると、ユーザーは選択ツールを閉じずに、フォト ライブラリからアイテムを継続的に選択したり、選択を解除したりできます。アプリの UI で選択または選択解除されたアイテムは、写真選択ツールと同期され、シームレスなユーザー エクスペリエンスが提供されます。

pickerState の deselectUri メソッドまたは deselectUris メソッドを使用して Uri の選択を解除し、ユーザーがアプリの UI からアイテムの選択を解除したことを埋め込み選択ツールに通知します。これらのメソッドを呼び出しても、onUriPermissionRevoked コールバックを介して、新たに取り消された URI がアプリに通知されることはないため、アプリの UI 状態を手動で更新する必要があります。

coroutineScope.launch {
    // Signal unselected media to the picker
    pickerState.deselectUris(uris)
    // Remove them from the list of selected media to be reflected in the app's UI
    _attachments.value -= uris
}

写真選択ツールをカスタマイズする

埋め込みの写真選択ツールには、パーソナライズのオプションが用意されています。外観や動作をカスタマイズして、アプリのデザインやユーザー エクスペリエンスに合わせることができます。

アクセント カラー

デフォルトでは、埋め込みの写真選択ツールは、システムが提供するダイナミック カラーに依存しています。ユーザーは、デバイスのテーマ設定オプションで、アプリ全体に適用されるダイナミック カラーを設定できます。アクセント カラーは、写真選択ツールのさまざまな主要要素に使用されます。その他の色はすべて、Android マテリアル ガイドラインに基づいて設定されます。選択ツールのアクセント カラーをカスタマイズするには、EmbeddedPhotoPickerFeatureInfo オプションを定義します。

val info = EmbeddedPhotoPickerFeatureInfo.Builder().setAccentColor(0xFF0000).build()

EmbeddedPhotoPicker(
    embeddedPhotoPickerFeatureInfo = info,
    ...
)
アクセント カラーを設定しない場合 アクセント カラー(ピーク) アクセント カラーあり(展開時)
アクセント カラーを設定していない写真選択ツールのスクリーンショット アクセント カラー(ピーク)が適用された写真選択ツールのスクリーンショット アクセント カラーが適用された写真選択ツールのスクリーンショット(展開時)

アクセント カラーは完全に不透明にする必要があります。アルファ(透明度)値は無視されます。輝度(明るさ)の値が 0.05 ~ 0.9 の色のみが許可されます。

サイズ

デフォルトでは、埋め込み選択ツールのサイズは制限されませんが、修飾子を指定して制限できます。

EmbeddedPhotoPicker(
    modifier = Modifier.height(500.dp),
    ...
)
制限なし(拡張) 500 dp の上限あり(展開時)
写真選択ツールのスクリーンショット 写真選択ツールのスクリーンショット

ビューの統合

ビューを使用して埋め込みの写真選択ツールを追加するには、レイアウト ファイルにエントリを追加します。

<view class="androidx.photopicker.EmbeddedPhotoPickerView"
    android:id="@+id/photopicker"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

次に、アクティビティの onCreate メソッドで、次の手順に沿って写真選択ツールを初期化します。

  1. レイアウトから EmbeddedPhotoPickerView への参照を取得する
  2. 選択イベントを処理する EmbeddedPhotoPickerStateChangeListener を追加する
  3. アクセント カラーなどのカスタム設定を含む EmbeddedPhotoPickerFeatureInfo を使用して、写真選択ツールを構成します。
// Keep track of the selected media
private val _attachments = MutableStateFlow(emptyList<Uri>())
val attachments = _attachments.asStateFlow()

private lateinit var picker: EmbeddedPhotoPickerView
private var openSession: EmbeddedPhotoPickerSession? = null

val pickerListener = object : EmbeddedPhotoPickerStateChangeListener {
    override fun onSessionOpened(newSession: EmbeddedPhotoPickerSession) {
        // Keep reference to the session to notify the embedded picker of user
        // interactions on the calling app
        openSession = newSession
    }

    override fun onSessionError(throwable: Throwable) {}

    override fun onUriPermissionGranted(uris: List<Uri>) {
        // Add newly selected media to our tracked list
        _attachments += uris
    }

    override fun onUriPermissionRevoked(uris: List<Uri>) {
        // Remove newly unselected media from our tracked list
        _attachments -= uris
    }

    override fun onSelectionComplete() {
        // Hide the embedded photo picker as the user is done with the
        // photo/video selection
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    setContentView(R.layout.main_view)
    picker = findViewById(R.id.photopicker)

    // Attach the embedded picker event listener to update the app's UI
    picker.addEmbeddedPhotoPickerStateChangeListener(pickerListener)

    // Customize embedded picker's features: accent color, max selectable items,
    // pre-selected URIs, filter out mime types
    picker.setEmbeddedPhotoPickerFeatureInfo(
        // Set a custom accent color
        EmbeddedPhotoPickerFeatureInfo.Builder().setAccentColor(0xFF0000).build()
    )
}

EmbeddedPhotoPickerSession のさまざまなメソッドを呼び出して、埋め込みピッカーを操作できます。

// Notify the embedded picker of a configuration change
openSession.notifyConfigurationChanged(newConfig)

// Update the embedded picker to expand following a user interaction
openSession.notifyPhotoPickerExpanded(/* expanded: */ true)

// Resize the embedded picker
openSession.notifyResized(/* width: */ 512, /* height: */ 256)

// Show/hide the embedded picker (after a form has been submitted)
openSession.notifyVisibilityChanged(/* visible: */ false)

// Remove unselected media from the embedded picker after they have been
// unselected from the host app's UI
openSession.requestRevokeUriPermission(removedUris)