Android13のPhoto picker（写真選択ツール）


# :star2:  はじめに

Android 13から以下のような、写真/動画選択時の新しいUIであるPhoto Picker（写真選択ツール）が追加されました。

|  単一選択  |  複数選択   |
| ---- | ---- |
|  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/9d9b1f55-03b3-f345-ae43-9c4233b3023d.png" width="300px">  |  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/e024a352-5e1b-140d-b3ca-c8eac50b8c63.png" width="300px">  |


[公式ドキュメント](https://developer.android.com/about/versions/13/features/photopicker) には `startActivityForResult/onActivityResult` を使った実装方法しか記載されてなかったので [^1] 、 `registerForActivityResult` と  `androidx.activity` の1.6.0-alpha03で追加された `ActivityResultContracts.PickVisualMedia` / `PickMultipleVisualMedia` を使った実装方法をやってみました。

# :tools: 実装

以下の順で説明していきます。

1. 依存関係追加
2. `registerForActivityResult`を定義
3. 起動

## 1. 依存関係追加

`ActivityResultContracts.PickVisualMedia` 等を使うには、`androidx.activity`の`1.6.0-alpha03`以降が必要なため追加しておきます。（記事作成時点では `1.6.0-alpha05`が最新でした）

```build.gradle
dependencies {
    implementation 'androidx.activity:activity-ktx:1.6.0-alpha05'
}
```

↓から最新版を確認できます。
https://developer.android.com/jetpack/androidx/releases/activity


## 2. `registerForActivityResult` の定義

### 単一選択の場合 :one: 


`registerForActivityResult`の引数に `ActivityResultContracts.PickVisualMedia`を指定します。 
選択した画像のURIが渡ってくるので、それを使って処理を書きます。今回は単純に `ImageView`　にセットする処理を書きました。


```kotlin
private val photoPickerLauncher =
    registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
        binding.imageView.setImageURI(uri)
    }
```

### 複数選択の場合 :1234: 

複数選択の場合は `ActivityResultContracts.PickMultipleVisualMedia`を指定し、引数に選択できる最大枚数を渡します。（下記の例だと3枚まで選択可）

```kotlin
private val photoPickerLauncher =
    registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(3)) { uriList ->
        // 何かしらの処理
}
```

URIのリストが返ってくるので、それを使って処理を書きます。


## 3. 起動

起動する時は、 `launch` の引数に `PickVisualMediaRequest`を指定します。

`PickVisualMediaRequest`は引数に `VisualMediaType`をとります。
以下の4つがあるようです。
* ImageAndVideo
* ImageOnly
* SingleMimeType
* VideoOnly

今回は画像を選択するので `ImageOnly` を指定しました。

```kotlin
binding.button.setOnClickListener {
    photoPickerLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
```

## コード全体（単一選択）

```MainActivity.kt
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private val photoPickerLauncher =
        registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
            binding.imageView.setImageURI(uri)
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        binding.button.setOnClickListener {
            photoPickerLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
        }
    }
}
```

# :movie_camera: 動作イメージ

## 単一選択

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/f711b323-3af3-2d35-3cc1-f84f4e6c9152.gif" width="300px">

画像を長押ししたらプレビューが表示されるようです。（上記例のワッフルを選択した時）
また、[ドキュメント](https://developer.android.com/about/versions/13/features/photopicker#define_sharing_limitations)にも以下の記載がある通り、単一選択の場合はハーフスクリーンで開くようです。（上にスワイプしたら全画面になります）

> Note: If you choose a maximum of 1, the photo picker opens in half-screen mode.

## 複数選択

複数選択の場合、`PickMultipleVisualMedia()`の引数に指定した最大枚数以上を選択しようとするとSnackBarで注意が出てくれるようです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/b1b93492-38c4-a9ed-577c-0dfc8dfe07fb.gif" width="300px">


以上です。

# :pencil: 参考

[Photo Picker - developer.android.com](https://developer.android.com/about/versions/13/features/photopicker)

[ActivityResultContracts.PickVisualMedia - developer.android.com](https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts.PickVisualMedia)


[^1]: 2022/08/15 にドキュメントが更新されて、`ActivityResultContracts.PickVisualMedia` 等を使った実装も追加されてました。