［Flutter］Assets （テキスト、画像）の利用方法

# はじめに

最近、少しずつ`Flutter`の公式ドキュメントを読み進めています。
今回は`Assets`の仕組みについて学んだのでまとめたいと思います。

# Assets とは

Assets とはアプリのデプロイ時にバンドルされるテキストデータや画像データなどのファイル群のことです。Assets にファイルを登録するとアプリから登録したファイルを読み込むことができるようになります。

# Assets で何ができる？
- JSON ファイルのテキストデータから設定パラメータを読み込むことができる。
- JPEG や GIF 、PNG、BMPなどの画像ファイルをアプリで表示できる。

# Assets に登録するには？

次の2ステップで Assets として利用するファイルを登録できる。

## Step1 `assets` ディレクトリにファイルを格納する

次の手順でファイルを`assets`ディレクトリに格納する。

1. プロジェクト名を右クリック、「New → Directories」を選択する。
2. ディレクトリ名に「assets」と入力し、「OK」を押す。
3. 作成した assets ディレクトリに Assets に登録したいファイルをコピーする。

今回は、次の JSON と PNG のファイルを格納しておこうと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/1b310c91-4638-bbee-98c8-a393b13243e2.png)

## Step2 `pubspec.yaml` にファイルのパスを記述する。

`pubspec.yaml`にバンドルするファイルのパスを記述する。

```yaml
flutter:
  assets:
    - assets/hello.json
    - assets/flutter-logo.png
```

`pubspec.yaml`に記述したパスは、ファイルの論理キーとして登録されます。
ファイルを読み込む際にはこのパス、つまり論理キーを指定して読み込みを行います。

# JSON（テキスト）ファイルを読み込む

`Flutter`では`Assets`にアクセスするための`rootBundle`というオブジェクトを所持しています。`JSON`(テキスト)ファイルを読み込む際には`rootBundle`を利用してアクセスします。

`JSON`(テキスト) ファイルは `rootBundle.loadString()`を利用して読み込みます。
引数には`pubspec.yaml`に登録した JSON をファイルの論理キーを指定します。

```dart
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;

Future<String> loadAsset() async {
  return rootBundle.loadString('assets/hello.json');
}
```

`rootBundle.loadString()`では`Future`オブジェクトを戻り値として返します。
`Future`オブジェクトは`Dart`で非同期処理を実行するクラスになります。

`Future`は`then`で非同期処理を実行して、
結果は`then`の引数で指定するコールバックで取得する仕組みになっています。

```dart:Future.then()のサンプル
Future<int> successor = future.then((int value) {
    return 42;
  }
);
```

今回は JSON ファイルの読み込みがうまく動作しているか確認しただけなので、
読み込み結果を`print`するコールバックを`then`に指定して非同期処理を実行させます。

```dart
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    loadAsset().then((t) => {print(t)});
  }
}
```

実行すると、次のように JSON ファイルの内容がコンソールに出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/da769451-b496-2258-694f-7c535ba886ea.png)

# PNG（画像）ファイルを表示する

PNG ファイルは `AssetImage()`を利用して読み込みます。
引数には`pubspec.yaml`に登録した PNG ファイルの論理キーを指定します。

```dart
    AssetImage('assets/flutter-logo.png')
```

`AssetImage` は `ImageProvider` を継承しているため、
`Image` ウィジェット の `image` に指定できるようになっています。
次のような感じで、 `Image`に`ImageAsset`を指定するだけで画像を表示できます。

```dart
@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title),),
      body: Column(children: <Widget>[
        Image(image: AssetImage('assets/flutter-logo.png')),
      ],),
    );
  }
```

実行すると、次のように PNG ファイルを読み込まれ、画像が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/22f2f9e5-9e6f-c9c0-9ecc-b10fc6853715.png)

# おわりに

- Assets にファイルを登録するには `assets`にファイルを格納するのと  
 `pubspec.xml`にファイルのパスを登録する2つの作業が必要。
- JSON（テキスト）ファイルを読み込むには `rootBundle` を利用して読み込む
- PNG(画像)ファイルを読み込むには`AssetImage`を利用して読み込む

同じ Assets でもテキストファイルと画像ファイルの読み込み方が違うようです。
これは Flutter には 異なるピクセル密度で動作させたときに利用する Assets を
切り替える仕組みがあるので画像に関しては AssetImage を通して読み込んでいるっぽいです。
AssetImage によって解像度が調整されるしくみについては、また別記事でまとめたいですね。。。

# 参考記事
- [Adding assets and images](https://flutter.dev/docs/development/ui/assets-and-images)
- [AssetImage class](https://api.flutter.dev/flutter/painting/AssetImage-class.html)