Flutterで画像を選択して表示させるまでの流れ

掲題の通り説明させていただきます。
また、今回は`image_picker`というパッケージを使用して
アカウント作成画面にて、プロフィール画像を選択するという構成でいきます。

## `image_picker`パッケージを使用する初動
`image_picker`の概要は、以下サイトから学びました。
https://pub.dev/packages/image_picker

### iOS版のみ、対応すべきこと
`プロジェクトのルート/ios/Runner/Info.plist`のファイルに下記を追記いたします。

```plist
<key>NSPhotoLibraryUsageDescription</key>
<string>このアプリはフォトライブラリにアクセスする必要があります</string>
<key>NSCameraUsageDescription</key>
<string>このアプリはカメラにファイルを追加する必要があります</string>
<key>NSMicrophoneUsageDescription</key>
<string>このアプリでは、マイクのフォトライブラリにファイルを追加する必要があります</string>
```

上記は、作成しているアプリが以下３点にアクセスする際の説明書きをしています。

- 写真のライブラリ
- カメラ
- マイク


## 実際に画像を選択して、表示させるまでのWidgetを作成する
まずは、上掲で挙げた`image_picker`パッケージをインポートします。

### `image_picker`をインポート
`'dart:io'`も必要なので、インポートしておきます。

```dart
import 'dart:io';

import 'package:image_picker/image_picker.dart';
```


### 画像を選択できるボタンを作成
最後あたりの条件文である`if (_pickedFile != null)`を記述しておかないと、
画像ライブラリの選択画面で「キャンセル」を押した際にエラーになってしまうので、きちんと記載しておきます。

```dart
  ...

  File _image;
  final _picker = ImagePicker();

  ...

                child: FlatButton(
                  onPressed: () => _getImageFromGallery(),
                  child: const Text(
                    '写真を選ぶ',
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      color: Color(0xffffffff),
                      fontWeight: FontWeight.w400,
                      fontSize: 15,
                      height: 1.2,
                    ),
                  ),
                ),

  ...


  Future _getImageFromGallery() async {
    final _pickedFile = await _picker.getImage(source: ImageSource.gallery);

    setState(() {
      if (_pickedFile != null) {
        _image = File(_pickedFile.path);
      }
    });
  }

  ...
```


### 画像を表示させる
ここでは、画像がないときにはグレーの枠を表示させて、
画像を選択したら、実際に選択した画像を表示させようとしております。

```dart
  ...


              Container(
                width: 150,
                height: 150,
                margin: const EdgeInsets.only(top: 90),
                child: _displaySelectionImageOrGrayImage()
              ),

  ...

  Widget _displaySelectionImageOrGrayImage() {
    if (_image == null) {
      return Container(
        decoration: BoxDecoration(
          color: const Color(0xffdfdfdf),
          border: Border.all(
            width: 2,
            color: const Color(0xff000000),
          ),
          borderRadius: BorderRadius.circular(75),
        ),
      );
    } else {
      return Container(
        decoration: BoxDecoration(
          border: Border.all(
            width: 2,
            color: const Color(0xff000000),
          ),
          borderRadius: BorderRadius.circular(75),
        ),
        child: ClipRRect(
          borderRadius: BorderRadius.circular(75),
          child: Image.file(
            _image,
            fit: BoxFit.fill,
          ),
        ),
      );
    }
  }

  ...
```


### 全体のソースコード
<details><div>

```dart
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

class RegisterProfile extends StatefulWidget {
  const RegisterProfile({Key key}) : super(key: key);

  @override
  _RegisterProfileState createState() => _RegisterProfileState();
}

class _RegisterProfileState extends State {
  File _image;
  final _picker = ImagePicker();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: <Widget>[
          Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Container(
                alignment: Alignment.topLeft,
                margin: const EdgeInsets.only(top: 81, left: 35, right: 35),
                child: const Text(
                  '最後に、\nプロフィール写真を設定しましょう！',
                  textAlign: TextAlign.left,
                  style: TextStyle(
                    fontWeight: FontWeight.w700,
                    fontSize: 24,
                  ),
                ),
              ),
              Container(
                width: 150,
                height: 150,
                margin: const EdgeInsets.only(top: 90),
                child: _displaySelectionImageOrGrayImage()
              ),
              Container(
                width: 144,
                height: 50,
                margin: const EdgeInsets.only(top: 47),
                decoration: BoxDecoration(
                  color: const Color(0xfffa4269),
                  border: Border.all(
                    width: 2,
                    color: const Color(0xff000000),
                  ),
                  borderRadius: BorderRadius.circular(15),
                ),
                child: FlatButton(
                  onPressed: () => _getImageFromGallery(),
                  child: const Text(
                    '写真を選ぶ',
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      color: Color(0xffffffff),
                      fontWeight: FontWeight.w400,
                      fontSize: 15,
                      height: 1.2,
                    ),
                  ),
                ),
              ),
            ],
          ),
          Container(
            child: _displayInSelectedImage()
          )
        ],
      ),
    );
  }

  Widget _displaySelectionImageOrGrayImage() {
    if (_image == null) {
      return Container(
        decoration: BoxDecoration(
          color: const Color(0xffdfdfdf),
          border: Border.all(
            width: 2,
            color: const Color(0xff000000),
          ),
          borderRadius: BorderRadius.circular(75),
        ),
      );
    } else {
      return Container(
        decoration: BoxDecoration(
          border: Border.all(
            width: 2,
            color: const Color(0xff000000),
          ),
          borderRadius: BorderRadius.circular(75),
        ),
        child: ClipRRect(
          borderRadius: BorderRadius.circular(75),
          child: Image.file(
            _image,
            fit: BoxFit.fill,
          ),
        ),
      );
    }
  }

  Widget _displayInSelectedImage() {
    if (_image == null) {
      return Column();
    } else {
      return Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Align(
            alignment: Alignment.topRight,
            child: Container(
              margin: const EdgeInsets.only(bottom: 20, right: 20),
              child: InkWell(
                child: Image.asset(
                  'assets/images/ic_send.png',
                ),
              ),
            ),
          ),
        ],
      );
    }
  }

  Future _getImageFromGallery() async {
    final _pickedFile = await _picker.getImage(source: ImageSource.gallery);

    setState(() {
      if (_pickedFile != null) {
        _image = File(_pickedFile.path);
      }
    });
  }
}

```
</div></details>


## 実装した実際の画面

### 画像を選択していない場合
<details><summary>画像</summary>
![スクリーンショット 2020-09-29 13.23.11-min.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425008/0a5d80d6-4869-afc2-88ac-e7b2f0b9dc2d.png)
</details>

### 画像を選択している場合
<details><summary>画像</summary>
![スクリーンショット 2020-09-29 13.22.33-min.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425008/cbfbdd2d-0346-ca74-629c-8b7a5fbde7ca.png)
</details>


以上で、Flutterで画像を選択して表示させるまでの流れの説明を終了させていただきます。