前回は、StatelessWidgetを使ったり、外部パッケージを使ったりしました。今回はStatefulWidget、つまり、動的に変化するWidgetを使ってみたいと思います。
Stateful Widget
Stateless Widgetは一度作成すると変化しないのに対し、Stateful Widgetは、冒頭で書いたとおり、変化します。Stateful Widgetを作るには、StatefulWidgetクラスとStateクラスが必要みたいですが、よくわからないのでやってみます。
main.dartの一番最後で少し改行を入れてstful
と入力すると・・・
新しいStateful Widgetを挿入するかを聞いてきますので、そのままENTERを押すと自動的にコードが挿入されます。これがStatefulWidgetクラスとStateクラスの雛形になります。便利ですね!
StatefulWidgetのクラス名を"RnadomWords"にすると・・・
自動的にStateクラスの方も書き換わるんですねー、これは便利だわー。
次に、MyAppクラスのbuildメソッドの中にあったfinal wordPair = WordPair.random();
を_RandomWordsState
クラスのbuildメソッドの中に移動して、
MyAppクラスで出力していたText(wordPair.asPascalCase)
を、_RandomWordsState
クラスの戻り値に指定します。
MyAppクラスのテキスト部分で、RandomWords()
(関数というかWidgetですかね)を呼び出します。
ここまでの最終的なコードはこんな感じです。
ではhot reloadします。hot reloadするたびに英単語のところがランダムに変わります。
ランダムな英単語を無限にスクロール
次はこのランダムな英単語をリストにして無限にスクロールしつつ生成するようにします。リスト表示には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, ), ); }
こうなります。
追加した関数について、公式の説明も含めて少し読んでみます。FlutterもDartもよくわかってないし、間違っても気にしない!
_buildSuggestions()
は ListViewを返す。builderメソッドでリストを動的に生成。itemBuilder
はコールバック関数になっていて、画面表示時に実行される。多分スクロールするたびに生成されているんだと思う。- iにリストのインデックスが入ってくるので、奇数のときは表示を変えるために分割線を入れる。
final index = i ~/ 2;
のところでリストのインデックスを2で割って整数化。これにより、分割線分を除いたリスト(つまり単語)の総数をカウント_suggestions
に入っている単語の総数よりもindex
が少なければ、generateWordPairs()
で単語を10個追加。- これにより無限にリストがスクロールできる
- _buildRowで個々のリスト(ListTile)の文字を大きくします。
では追加した関数を使うように、_RandomWordsState
クラスのbuild
メソッドを書き換えましょう。変更前はこんな感じで、直接wordPair()
を読んで単語を1つテキストで返して表示しているだけです。
以下のように、_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()
に置き換えます。ケツカンマはあってもなくてもいいみたいです。
最終的なコードはこんな感じです。
ではテストで実行してみます。
ちゃんとスクロールしてますね!
まとめ
だんだんスマホアプリらしくなってきましたね。Get Startedはここで終わりみたいですが、Codelabsに続きがあるようなので次回も引き続き。
codelabs.developers.google.com
まだまだ先は長い・・・