目次

  1. 目次
  2. 概要
  3. インストール方法
  4. 開発環境の構築
  5. 最初の Flutter アプリ開発
  6. 今回のまとめ

概要

Flutterは、 Google が開発したモバイルアプリ向けの UI フレームワークです。 Flutter を使うことで、 iOS と Android で同じコードを使用して、アプリの開発を行うことができます。 Flutter の特徴は、以下のような特徴があります。

  1. 高速な開発サイクル
    • Hot Reload の仕組みにより、コードの編集とアプリへの反映をリアルタイムに確認することができます。
  2. リッチな UI
    • Flutter SDK で提供されている Widget を使用することで、リッチな UI を作成することができます。
    • Material Components や Cupertino という Widget を使うことで、 Android や iOS のプラットフォームネイティブな見た目のアプリを開発できます。
  3. モダンなフレームワーク
  4. ネイティブの機能のサポート
    • iOS や Android のネイティブな機能にアクセスすることができます。
    • また、既存の SDK を利用することもできます。
  5. 一貫した開発環境
    • Flutter は、ビルドからデプロイまでの開発をサポートします。
  6. オープンソース
    • Flutter のソースコードは、GitHubにホストされています。

インストール方法

Flutter のインストールは、以下の手順で行います。

  1. Flutter SDK Archiveから、インストールしたい Flutter のパッケージをダウンロードする。
    • 以下の組み合わせから、適切なものを選択してください。
      • Windows 、 macOS 、 Linux
      • Beta チャンネル、 Dev チャンネル、 Master チャンネル
      • 使っている OS の Beta チャンネルのものを使えば問題ないかと思います。
  2. ダウンロードしてきたパッケージを任意の場所に展開する。
  3. flutterのツール群を利用できるように、パスの設定を行う。
  4. 依存しているパッケージなどをインストールするのに、flutter doctorを実行する。

Windows

Windows 環境向けに、flutter_console.bat というバッチファイルが提供されています。 このバッチファイルを開くと、flutterにパスが通った状態で、コンソールが立ち上がります。 環境変数を更新する必要がないので、試しに使ってみたい、という場合は、こちらを利用するのが良いと思います。 本格的に Flutter を使った開発を行う際は、環境変数を更新するのが良いでしょう。

iOS アプリの開発

iOS アプリの開発は、 macOS でのみ可能です。

Xcode のインストール

  1. Mac App Storeから、 Xcode のインストールを行います。
  2. Xcode を起動し、ライセンスに同意します。
    • sudo xcodebuild -license をターミナルで実行することで、 Xcode を起動せずに、ライセンスに同意することもできます。

シミュレーターの設定

  1. open -a Simulator をターミナル上で実行し、シミュレーターを起動させます。
  2. シミュレーターでは、64bit 端末を使用する。
  3. flutter run を実行し、アプリをシミュレーターで実行する。

iOS 端末の設定

iOS 端末で、 Flutter で作成したアプリを実行する場合には、homebrewを使って、ツールをインストールすることが必要になります。

  1. homebrewをインストールする。
  2. 以下のコマンドを実行し、必要なツールのインストールを行う。
brew update
brew install --HEAD libimobiledevice
brew install ideviceinstaller ios-deploy cocoapods
pod setup

Flutter を使用してプロジェクトを作成すると、ios/Runner.xcworkspace というワークスペースファイルが作成されます。 Xcode でこのファイルを開き、サイニングの設定を行ってください。 アプリの実行は、シミュレーターと同様、flutter run で行います。

Android アプリの開発

Android Studio のインストール

  1. Android Studioをダウンロードし、インストールを行う。
  2. Android Studio を起動し、Android Studio Setup Wizard から、以下のものをインストールする。
    • 最新の Android SDK
    • Android SDK Platform-Tools
    • Android SDK Build-Tools

Android 端末の設定

  1. 端末上で、開発者向けオプションを有効にし、 USB デバッグを有効にする。
  2. 端末を USB ケーブルで、 PC と接続し、 PC から端末にアクセスできるようにする。
  3. ターミナル上で、flutter devices を実行し、 Flutter が端末を認識していることを確認する。
  4. flutter run を実行し、アプリを端末で実行する。

Android エミュレーターの設定

  1. PC 上で、Hardware Accelerationを有効にする。
  2. AVD Manager を起動し、新しい仮想端末を作成する。
  3. 適当なハードウェアを選択し、 Next を押す。
  4. 任意のシステムイメージを選択し、 Next を押す。
    • x86、または、 x86_64のシステムイメージが水晶となっています。
  5. Emulated Performance の項目を、 Hardware – GLES 2.0にし、アクセラレーションを有効にする。
  6. 仮想端末の検証をし、 Finish を押す。
  7. AVD Manager から、作成した仮想端末を起動させる。
  8. flutter run を実行し、アプリを仮想端末で実行する。
    • 接続されたデバイス名は、 Android SDK built for <platform> となる。

開発環境の構築

Flutter アプリの開発では、任意のエディターと Flutter ツールチェーンを使うことになります。 公式がプラグインを提供しているエディターもあり、そのようなプラグインを使用すると、コード補完、構文ハイライトなどの便利な機能を活用できます。 公式なプラグインとしては、以下のエディター/開発環境に向けたものが提供されています。

ここでは、上記の開発環境でのプラグインの導入方法と使い方を解説します。

Android Studio/IntelliJ IDEA

プラグインのインストール

  1. Preferences を開きます。
  2. Plugins から、「 Browse repositories…」ボタンを押し、プラグイン選択ダイアログを開きます。
  3. Flutter プラグインをインストールします。
    • Flutter プラグインと同時に、 Dart プラグインをインストールされます。
    • 検索から、Flutter と入力すると、すぐに探せます。
  4. Android Studio を再起動します。

アプリの開発

  1. File > New > Project… を選択します。
  2. New Project から、 Flutter を選択します。
  3. プロジェクトの設定を行い、プロジェクトを作成します。
  4. ツールバーから、端末の選択、アプリの実行、デバッグを行います。
    • 通常の Android アプリの開発と同じような流れで実行できます。

Visual Studio Code

プラグインのインストール

  1. Command Palette を表示します。
  2. アクションExtensions: Install Extensionを選択します。
    • Extensionsを入力して、アクションを絞り込むと、インストールアクションが探しやすいです。
  3. 検索フィールドに、Dart Codeを入力し、プラグインをインストールします。
  4. インストール後、 Visual Studio Code のリロードを行います。
  5. リロード後、 Command Palette で、Flutter: Run Flutter Doctorを選択し、プラグインが正常にインストールできていることを確認します。

アプリの開発

  1. Command Palette から、アクションFlutter: New Projectを選択します。
  2. プロジェクト名を入力します。
    • プロジェクト名は、大文字が使えないので、注意してください。
  3. プロジェクトの保存先を選択します。
  4. プロジェクトの作成後、プロジェクトにあるlib/main.dartが表示されます。
    • ファイルの作成などが行われるため、lib/main.dartが表示されるまで、しばらく時間がかかります。
  5. アプリの実行は、メニューから、デバッグの開始を選択するか、 F5キーを押して行います。
    • 事前に、端末、または、エミュレーター/シミュレーターを起動しておく必要があります。

最初の Flutter アプリ開発

ここでは、簡単なアプリの開発を通して、 Flutter の使い方を解説します。

プロジェクトの作成方法

Android Studio/IntelliJ IDEA

  1. File > New > Project… を選択します。
  2. New Project から、 Flutter を選択します。
  3. プロジェクトの設定を行い、プロジェクトを作成します。

Visual Studio Code

  1. Command Palette から、アクションFlutter: New Projectを選択します。
  2. プロジェクト名を入力します。
    • プロジェクト名は、大文字が使えないので、注意してください。
  3. プロジェクトの保存先を選択します。

コマンドライン

適当なディレクトリに移動し、以下のコマンドを実行します。

flutter create project_name

flutter createで指定できるオプションは、-hで確認できます。

flutter create -h

project_nameで指定した名前のディレクトリが、カレントディレクトリ直下に作成され、その中に、アプリに必要なファイルやソースコードが出力されます。

アプリの実行/デバッグ方法

プロジェクトが作成された時点のアプリを実行して、開発中にアプリをテストする流れを確認しましょう。

  1. アプリを動作させる端末の準備
    • Android であれば、emulatorコマンドで、仮想端末を起動させます。
    • iOS であれば、open -a Simulatorを実行し、シミュレーターを起動させます。
  2. アプリの実行
    • Android Studio/IntelliJ を使っている場合は、ツールバーから、端末の選択をし、アプリを実行します。
    • Visual Studio Code を使っている場合は、F5を押して、デバッグの開始を行います。
    • コマンドラインの場合は、flutter runを実行します。
  3. アプリの動作を確認
    • 起動したアプリを動かします。
    • Floating Action Button (画面右下の丸ボタン)を押すと、カウントが+1されます。
  4. Hot Reload
    • 画面上に表示されている文字列を書き換えて、 Hot Reload で、変更が反映されることを確認します。
    • lib/main.dartを開き、93行目の'You have pushed the button this many times:'という部分を適当な文字列に書き換えて保存します。
    • すると、アプリの表示が、書き換えた文字列に変わることを確認します。
    • Hot Reload の詳細は、Using Hot Reloadを参考にしてください。

Hot Reload Sample

サンプルアプリ開発

プロジェクトの作成方法、アプリの実行方法を簡単に確認したので、アプリの開発を行っていきます。 ここでは、公式サイトWrite Your First Flutter Appにあるアプリを作ってみます。

Write Your First Flutter Appで作成するアプリは、以下のようなアプリです。

  • 任意の単語を2つ繋げた単語のリストを表示します。
    • 無限リストとして、単語のリストを表示します。
  • 単語のリストを選択すると、お気に入りに登録されます。
    • お気に入り登録済みの単語を選択すると、お気に入りから削除されます。
  • ナビゲーションバーから、お気に入りに登録した単語のリストを確認できます。

以下に、ここで作成するサンプルアプリのスクリーンショットを掲載します。

Flutter Sample

プロジェクト作成

前述のやり方で、プロジェクトを作成します。 ここでは、startup_namerという名前のプロジェクトを作成してください。

外部パッケージの追加と利用

多くのアプリの開発現場では、外部パッケージを使用して、アプリの開発を行います(もちろん、外部パッケージを全く使わない、という場合もありますが、そのようなケースは少ないでしょう)。 例えば、 iOS アプリであれば、ある機能を持った View やアプリで使用される汎用的な機能(API リクエストなど)を提供するフレームワークを、CocoapodsCarthageで管理し、開発を行います。 ここでは、どのようなパッケージを利用するのか? また、どのバージョンを利用するのか? ということを、開発チームで、共通の環境となるようにする、という目的で用いられます。 Flutter SDK には、このようなパッケージ管理のためのツールも同梱されています。 このパッケージ管理ツールは、pubspec.yamlに記載された情報を元に、パッケージの管理を行っています。

今回、作成するアプリでは、english_wordsという英単語を扱うパッケージを使用します。 アプリが使用するパッケージは、dependenciesのセクションに以下のように記載します。

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.0
  english_words: ^3.1.0

パッケージのバージョンの指定方法などは、Pub Versioning Philosophyを参考にすると良いでしょう。

pubspec.yamlを保存すると、利用しているエディタによっては、自動的に、パッケージの取得処理が実行されます。 パッケージの取得処理が自動的に行われない場合は、エディタから、Get Packagesコマンドを手動で実行します。

追加したパッケージをアプリから利用する場合は、import文で、パッケージを取り込むことで利用できます。

import 'package:english_words/english_words.dart';

上記のimport文で、english_wordsを取り込むことで、english_wordsが提供する機能を利用できます。 簡単に、english_wordsの利用方法を確認するために、lib/main.dartで、単語のペアを生成し、それを表示してみます。

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

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // ランダムで、単語のペアを生成する
    final wordPair = new WordPair.random();
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          // ランダムに生成した単語のペアをパスカルケースにして、表示する
          child: new Text(wordPair.asPascalCase),
        ),
      ),
    );
  }
}

単語のリストを表示

今回作成するアプリでは、単語のリストをランダムに生成するため、リストは無限の長さを持ちます。 そのため、スクロールをし、現在のリストの長さよりも先の要素が必要になった時点で、単語を作成する、というようにします。 このため、リストは、現在の状態を持ち、スクロールによって、その状態を更新しなければなりません。

Flutter では、アプリは、Widgetから構成されます。 Widgetは、状態を持たないStatelessWidgetと、状態を持つStatefulWidgetの2種類があります。 今回作成するアプリでは、前述のように、現在表示している単語のリストを状態として持ちます。 つまり、StatefulWidgetを使って、リストの表示を行います。

StatefulWidgetを使う場合は、以下のクラスを継承したクラスを用意します。

  • StatefulWidget
    • 状態を持つWidgetの定義
  • State
    • StatefulWidgetの状態とロジック

今回作成するアプリでは、それぞれ、以下のようなクラスを作成します。

  • RandomWords (StatefulWidgetを継承したクラス)
    • createState()メソッドで、自身の状態を表すRandomWordsStateのインスタンスを返す。
  • RandomWordsState (Stateを継承したクラス)
    • 現在表示している単語のリストを保持します。
    • お気に入りに登録された単語のリストを保持します。
    • RandomWordsとして、表示する UI を構築します。
    • お気に入りへの登録、お気に入りからの削除、などのユーザー操作を受け付けます。
RandomWordsの実装

RandomWordsの実装は、以下の要件を満たすように行います。

  1. StatefulWidgetを継承したクラスを定します。
  2. createState()をオーバーライドし、RandomWordsStateのインスタンスを返す。

以下のような内容を、lib/main.dartに追加します。

// StatefulWidget を継承した RandomWords クラスを定義
class RandomWords extends StatefulWidget {
  // createState()をオーバーライドし、 RandomWordsState のインスタンスを返す。
  @override
  createState() => new RandomWordsState();
}
RandomWordsStateの実装

RandomWordsStateの実装は、以下の要件を満たすように行います。

  1. Stateを継承したクラスを定義します。
  2. StatefulWidgetを継承したRandomWordsに結びつけます。
  3. リストとして表示する単語を保持します。
  4. お気に入りに登録された単語のリストを保持します。
  5. RandomWordsの UI を定義します。
  6. ユーザーのタップ操作により、お気に入りへの登録、お気に入りからの削除を行います。

1.と2.は、以下のようなRandomWordsStateを定義することで、実現できます。

class RandomWordsState extends State<RandomWords> {
}

この定義により、Stateを継承したRandomWordsStateが定義され、State<RandomWords>という記述から、RandomWordsというStatefulWidgetと結びついていることが保証されます。

次に、表示する単語を保持するプロパティとお気に入りに登録された単語を保持するプロパティを定義します。

class RandomWordsState extends State<RandomWords> {
  // リストに表示する単語のリスト
  final _suggestions = <WordPair>[];
  // お気に入りに登録された単語のセット
  final _saved = new Set<WordPair>();

  // 単語を表示させるテキストのスタイルの設定
  final _biggerFont = const TextStyle(fontSize:  18.0);
}

画面上に、単語のリストなど、何かのリストを表示するときは、ListViewを使用します。 今回作るアプリでは、リストから、表示するWidgetを決めるので、ListView.builderを使うと簡単に実装できます。

以下のようなメソッドを定義し、ListViewのインスタンスを返すメソッドを実装します。

Widget _buildSuggestions() {
  return new ListView.builder(
    // ListView の領域に、16pt の余白を作る
    padding: const EdgeInsets.all(16.0),
    // リストの i 番目の場所の要素を表示する Widget を作る
    itemBuilder: (context, i) {
      // 要素間に、分割線をいれたいので、奇数番目の場所は、分割線を返す
      if (i.isOdd) return new Divider();
      // 偶数番目のインデックスを_suggestions の List のインデックスに変換する
      final index = i ~/ 2;
      if (index >= _suggestions.length) {
        // リストよりも先の要素を表示しようとしていたら、新しく単語を生成する
        _suggestions.addAll(generateWordPairs().take(10));
      }
      // index 番目の単語を表示させる
      return _buildRow(_suggestions[index]);
    },
  );
}

上記のメソッドは、以下のようなことを行なっています。

  • ListView.builderを呼んで、ListViewのインスタンスを生成します。
  • paddingパラメーターを指定して、ListViewの余白を作ります。
  • itemBuilderパラメーターに、i番目のインデックスで表示するWidgetを返す関数/メソッドを指定します。
    • 今回は、要素間に、1pt の分割線をいれたいので、iが奇数であれば、Dividerのインスタンスを返す。
    • iが偶数であれば、~/で、2で除算を行なった結果を整数として、計算します。
    • indexが、現在のリストの要素数以上であれば、新たに10個単語を生成して、リストに追加します。
    • _suggestionsindex番目の要素を_buildRowに渡し、単語を表示させるWidgetを生成します。

リスト全体を表示するメソッドの実装を行なった次は、単語を表示する箇所を実装します。 ListViewに表示する場合は、ListTileを使います。 ListTileは、アイコンとテキストをListViewに表示するのに便利な Widget です。 これを使って、単語を表示します。

Widget _buildRow(WordPair pair) {
  // お気に入りに登録されているかどうか?
  final alreadySaved = _saved.contains(pair);

  return new ListTile(
    // 本文として表示するテキストの設定
    title: new Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    // ListTile の右側に表示するアイコンの設定
    trailing: new Icon(
      // アイコン画像の設定
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      // アイコンの色の設定
      color: alreadySaved ? Colors.red : null,
    ),
    // ListTile をタップされた時の動作の定義
    onTap: () {
      // 状態の更新を通知する
      setState(() {
        if (alreadySaved) {
          // お気に入りから削除
          _saved.remove(pair);
        } else {
          // お気に入りに追加
          _saved.add(pair);
        }
      });
    },
  );
}

上記のメソッドでは、以下のことを行なっています。

  • pairが、_savedに含まれているかどうかを判定します。
    • ListTileの右側に表示するお気に入りアイコンの表示の制御に使用します。
    • ListTileをタップした後の状態の更新で使用します。
  • ListTileのインスタンスを生成します。
    • ここで、生成されたインスタンスが、単語の表示に使われます。
    • titleパラメーターに、表示する単語を指定します。
    • trailingパラメーターに、右側に表示するお気に入りアイコンを指定します。
      • アイコンの表示は、alreadySavedの値によって変わります。
    • onTapパラメーターに、タップされた時の処理を定義します。
      • onTapに指定した処理の中で、setState()を呼び出し、状態の更新をフレームワークに通知します。
      • setState()の呼び出しにより、 UI の更新が行われます。

ここまでの部分で、RandomWordsStateの実装は、概ね完了したので、アプリ起動時に、RandomWordsを表示させるようにRandomWordsStateに、build()メソッドを定義します。 build()メソッドでは、このクラスで表示する Widget を返します。 アプリの画面に対応する場合は、画面全体を表示するための Widget のインスタンスを返します。 Material Design なアプリを実装する場合、Scaffoldを使用すると、必要な機能が、直感的に実装できます。

@override
Widget build(BuildContext context) {
  return new Scaffold(
    appBar: new AppBar(
      title: new Text('Startup Name Generator'),
    ),
    body: _buildSuggestions()
  );
}
  • appBarパラメーターには、AppBarを設定します。
    • App Bar の詳細については、 Material Design のApp barに詳細が記載されています。
  • bodyパラメーターには、メインとなるコンテンツを表示する Widget を指定します。
    • 今回は、_buildSuggestions()メソッドで、リストを表示するListViewのインスタンスを生成しているので、これを指定します。

次に、アプリ全体の定義を行います。

// main 関数の定義
// runApp で、アプリ起動時に表示する画面を指定しておく
void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // build メソッドでアプリを生成する
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter App',
      home: new RandomWords(),
    );
  }
}

MaterialAppのインスタンスを生成することで、 Material Design に準拠したアプリの Widget を生成します。 homeパラメーターには、アプリの起動時に表示する画面のWidgetのインスタンスを指定します。

お気に入りリストの表示

お気に入りに登録された単語を表示する画面の実装と、その画面への遷移を実装します。 App bar にボタンを追加し、そのボタンをタップされた時に、お気に入りリストの画面へ遷移させます。 画面への遷移とお気に入りリストの画面自体は、_pushSaved()メソッドで実装し、まず、 App bar にボタンを追加します。

class RandomWordsState extends State<RandomWords> {
  ...

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Startup Name Generator'),
        actions: <Widget>[
          new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),
        ],
      ),
      body: _buildSuggestions()
    );
  }

App bar にボタンを追加する場合は、単純に、actionsパラメーターに、ボタンを追加するだけです。 IconButtononPressedに、後ほど作成するメソッド_pushSavedを指定します。

Flutter での画面遷移は、Navigatorを使って行います。 Navigatorは、ナビゲーションスタックを管理し、 push/pop などのアニメーションを行っています。

お気に入りリスト画面への遷移と、お気に入りリスト画面の表示は、以下のように行います。

void _pushSaved() {
  // Navigator のスタックに、お気に入りリストの画面を push する
  Navigator.of(context).push(
    // route の定義を行う
    new MaterialPageRoute(
      builder: (context) {
        // お気に入りに登録されている単語を表示する ListTile のインスタンスを生成する
        final tiles = _saved.map(
          (pair) {
            return new ListTile(
              title: new Text(
                pair.asPascalCase,
                style: _biggerFont,
              )
            );
          }
        );
        // divideTiles メソッドを使って、要素間に分割線を追加する
        final divided = ListTile.divideTiles(
          context: context,
          tiles: tiles,
        )
        .toList();

        // 遷移先の画面を生成する
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('Saved Suggestions'),
          ),
          body: new ListView(children: divided),
        );
      }
    )
  );
}

最終的なコード

上記までの実装をまとめると、lib/main.dartは、以下のようになります。

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

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Fulluter App',
      theme: new ThemeData(primaryColor: Colors.white),
      home: new RandomWords(),
    );
  }
}

class RandomWords extends StatefulWidget {
  @override
  createState() => new RandomWordsState();
}

class RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];

  final _saved = new Set<WordPair>();

  final _biggerFont = const TextStyle(fontSize: 18.0);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('Startup Name Generator'),
          actions: <Widget>[
            new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),
          ],
        ),
        body: _buildSuggestions());
  }

  Widget _buildSuggestions() {
    return new ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemBuilder: (context, i) {
        if (i.isOdd) return new Divider();
        final index = i ~/ 2;
        if (index >= _suggestions.length) {
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_suggestions[index]);
      },
    );
  }

  Widget _buildRow(WordPair pair) {
    final alreadySaved = _saved.contains(pair);

    return new ListTile(
      title: new Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
      trailing: new Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      onTap: () {
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );
  }

  void _pushSaved() {
    Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
      final tiles = _saved.map((pair) {
        return new ListTile(
            title: new Text(
          pair.asPascalCase,
          style: _biggerFont,
        ));
      });
      final divided = ListTile
          .divideTiles(
            context: context,
            tiles: tiles,
          )
          .toList();

      return new Scaffold(
        appBar: new AppBar(
          title: new Text('Saved Suggestions'),
        ),
        body: new ListView(children: divided),
      );
    }));
  }
}

今回のまとめ

今回は、 Android/iOS アプリを開発するための UI フレームワーク Flutter を紹介しました。 また、簡単なサンプルアプリの作成を通して、 Flutter が、どのようなものか、ということを解説しました。 サンプルアプリの開発からも分かるように、 Flutter は、全てが Widget で構成される、という特徴や、 Hot Reload など、強力な機能を持ったフレームワークです。 実際に、 Flutter を採用しているアプリが、すでに公開されており、十分に実用できるフレームワークではないかと思います。