kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

Flutterに入門してみる ④最初のアプリ Part2

f:id:kun432:20201207110008p:plain

前回は、StatelessWidgetを使ったり、外部パッケージを使ったりしました。今回はStatefulWidget、つまり、動的に変化するWidgetを使ってみたいと思います。

flutter.dev

Stateful Widget

Stateless Widgetは一度作成すると変化しないのに対し、Stateful Widgetは、冒頭で書いたとおり、変化します。Stateful Widgetを作るには、StatefulWidgetクラスとStateクラスが必要みたいですが、よくわからないのでやってみます。

main.dartの一番最後で少し改行を入れてstfulと入力すると・・・

f:id:kun432:20201211212426p:plain

新しいStateful Widgetを挿入するかを聞いてきますので、そのままENTERを押すと自動的にコードが挿入されます。これがStatefulWidgetクラスとStateクラスの雛形になります。便利ですね!

f:id:kun432:20201211212551p:plain

StatefulWidgetのクラス名を"RnadomWords"にすると・・・

f:id:kun432:20201211213133p:plain

自動的にStateクラスの方も書き換わるんですねー、これは便利だわー。

次に、MyAppクラスのbuildメソッドの中にあったfinal wordPair = WordPair.random();_RandomWordsStateクラスのbuildメソッドの中に移動して、

f:id:kun432:20201211233930p:plain

f:id:kun432:20201211233939p:plain

MyAppクラスで出力していたText(wordPair.asPascalCase)を、_RandomWordsStateクラスの戻り値に指定します。

f:id:kun432:20201211234757p:plain

f:id:kun432:20201211234809p:plain

MyAppクラスのテキスト部分で、RandomWords()(関数というかWidgetですかね)を呼び出します。

f:id:kun432:20201211235017p:plain

ここまでの最終的なコードはこんな感じです。

ではhot reloadします。hot reloadするたびに英単語のところがランダムに変わります。

f:id:kun432:20201212000143g:plain

f:id:kun432:20201212000131g:plain

ランダムな英単語を無限にスクロール

次はこのランダムな英単語をリストにして無限にスクロールしつつ生成するようにします。リスト表示にはListView Widgetを使います。

まず、_RandomWordStateクラスの先頭に以下の2行を追加します。_suggestionsはランダムな英単語の配列を入れておく感じなのかな。_biggerFontはフォントサイズを大きくするためのスタイルを変数に入れてるんでしょうね。

  final _suggestions = <WordPair>[];
  final _biggerFont = TextStyle(fontSize: 18.0);

次にランダムな英単語をListViewで返す関数を追加します。以下のコードを_RandomWordsStateクラスの最後に追加します。

Widget _buildSuggestions() {
  return ListView.builder(
      padding: EdgeInsets.all(16.0),
      itemBuilder: /*1*/ (context, i) {
        if (i.isOdd) return Divider(); /*2*/

        final index = i ~/ 2; /*3*/
        if (index >= _suggestions.length) {
          _suggestions.addAll(generateWordPairs().take(10)); /*4*/
        }
        return _buildRow(_suggestions[index]);
      });
}

さらにその下にリストの各行を生成する_buildRow()関数を追加します。

Widget _buildRow(WordPair pair) {
  return ListTile(
    title: Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
  );
}

こうなります。

f:id:kun432:20201212104625p:plain

追加した関数について、公式の説明も含めて少し読んでみます。FlutterもDartもよくわかってないし、間違っても気にしない!

  • _buildSuggestions() は ListViewを返す。builderメソッドでリストを動的に生成。
  • itemBuilderはコールバック関数になっていて、画面表示時に実行される。多分スクロールするたびに生成されているんだと思う。
    • iにリストのインデックスが入ってくるので、奇数のときは表示を変えるために分割線を入れる。
    • final index = i ~/ 2; のところでリストのインデックスを2で割って整数化。これにより、分割線分を除いたリスト(つまり単語)の総数をカウント
    • _suggestionsに入っている単語の総数よりもindexが少なければ、generateWordPairs()で単語を10個追加。
    • これにより無限にリストがスクロールできる
  • _buildRowで個々のリスト(ListTile)の文字を大きくします。

では追加した関数を使うように、_RandomWordsStateクラスのbuildメソッドを書き換えましょう。変更前はこんな感じで、直接wordPair()を読んで単語を1つテキストで返して表示しているだけです。

f:id:kun432:20201212124029p:plain

以下のように、_buildSuggestions()を使ってリストを生成し、直接Scaffold Widgetとして返すようにします。

class _RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _biggerFont = TextStyle(fontSize: 18.0);
  @override
  Widget build(BuildContext context) {
    return Scaffold(                              // 変更
      appBar: AppBar(                             // 変更
        title: Text('Startup Name Generator'),    // 変更
      ),                                          // 変更
      body: _buildSuggestions(),                  // 変更
    );                                            // 変更
  }
(snip)

最後にMyAppクラスのScaffoldの部分をRandomWords()に置き換えます。ケツカンマはあってもなくてもいいみたいです。

f:id:kun432:20201213010236p:plain

f:id:kun432:20201213010245p:plain

最終的なコードはこんな感じです。

ではテストで実行してみます。

f:id:kun432:20201213010008g:plain

f:id:kun432:20201213005617g:plain

ちゃんとスクロールしてますね!

まとめ

だんだんスマホアプリらしくなってきましたね。Get Startedはここで終わりみたいですが、Codelabsに続きがあるようなので次回も引き続き。

codelabs.developers.google.com

まだまだ先は長い・・・