[Flutter入門(2)] Write your first Flutter app, part 1をやってみる
Flutterの公式サイトに、チュートリアルよりも前にやってみる用のコンテンツとして Write your first Flutter app, part 1 というものが用意されているので、この内容を簡単なコードの解説を交えながら紹介していきます。
Step 1:アプリを作る
まず、Getting Started with your first Flutter app の手順でサンプルアプリを作ります。このとき、アプリ名は my_app ではなく今回は startup_namer にします。
$ flutter create startup_namer
サンプルアプリができたら、iOSシミュレータを立ち上げて、アプリを起動しましょう。
$ open -a Simulator
$ cd startup_namer
$ flutter run
これでとりあえずサンプルアプリがそのまま動いている状態ですね。
ここまで来たら、 lib/main.dart の中身を以下のコードでごっそり置き換えてしまいましょう。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: Text('Hello World'),
),
),
);
}
}
コードを変更したら、 flutter run しているターミナルで r キーをタイプすることでホットリロード(起動中のアプリにソースコードの変更内容を即時反映させるFlutterのデバッグ用機能)ができます。
$ flutter run
:
:
:
Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h Repeat this help message.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
An Observatory debugger and profiler on iPhone SE (2nd generation) is available at: http://127.0.0.1:64038/E4xtLgtlcWU=/
# ここで r キーをタイプ
Performing hot reload...
Reloaded 1 of 503 libraries in 164ms.
# 起動中のアプリに変更が反映される
ちなみに、VS CodeなどのIDEにFlutterプラグインを導入して使っている場合は、ソースコードの変更を保存したら即座にホットリロードが実行されるようにすることも可能です。
例えばVS Codeの場合なら、ターミナルで
flutter runする代わりに実行 > デバッグの開始(またはF5)でアプリを起動すれば、ソースコードを変更して保存したら即座にアプリの状態に反映されます。
VS Code自体のセットアップ方法は こちらの公式ドキュメント をご参照ください。
lib/main.dart を上記の内容に変更すると、アプリの画面は以下のような内容になります。

コードの内容のうちいくつかポイントとなる点を確認しておきましょう。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: Text('Hello World'),
),
),
);
}
}
-
MaterialAppクラスを使って、Materialデザイン に準拠したアプリを作成している。FlutterはMaterialデザインを実装した様々なウィジェットを提供している -
main()メソッドはアロー記法(=>)を使っている(JavaScriptのアロー関数と同様、関数の処理が1行の場合はこの省略記法が使える) -
MyApp自体がStatelessWidgetクラスを継承していて、アプリそれ自体が「ウィジェット」になっている点に注目。Flutterではほとんどすべてのもの(alignment, padding, layoutなども含む)がウィジェットである -
ScaffoldウィジェットはFlutter標準のMaterialライブラリにより提供されている。このウィジェットはappBartitlebodyプロパティを持っていて、ホームスクリーンの見た目を簡単に作成できる - ウィジェットのメインの仕事は
build()メソッドを提供することである。build()メソッドでは、他のウィジェットを組み合わせるなどしてウィジェット全体の見た目を構築する - この例では
bodyに「Textウィジェットを子として持つようなCenterウィジェット」を渡している。Centerウィジェットは子要素を中央寄せしてくれるウィジェットである
Step 2:外部パッケージを使ってみる
english_words という外部パッケージを導入してみます。
pubspec.yaml というファイルに以下のような1行を追記します。
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
+ english_words: ^3.1.5
追記したら、アプリのディレクトリ直下( flutter run しているのと同じ階層)で以下のコマンドを実行してパッケージをインストールします。
$ flutter pub get
VS CodeにFlutterプラグインを入れて使っている場合は、
pubspec.yamlの変更を保存したときに自動でflutter pub getが実行されるので、自分で別途実行する必要はありません✋
次に、 lib/main.dart でこのパッケージを利用するために、ファイルの先頭に以下の import 文を追記します。
import 'package:flutter/material.dart';
+ import 'package:english_words/english_words.dart';
最後に、このパッケージを使用して画面に出力する文字を Hello World ではなくランダムな単語の組み合わせにしてみます。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final wordPair = WordPair.random();
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
+ child: Text('Hello World'),
+ child: Text(wordPair.asPascalCase),
),
),
);
}
}
下図のように、 Hello World の代わりにランダムな単語を並べた文字列が表示されるようになりました。

ホットリロードする度に表示される文字列が変わるはずです。試してみてください。
上手くホットリロードされない場合は、一度
flutter runを終了(ターミナル上でCtrl + Cで終了できます)させて、再度flutter runしてアプリを再起動してみてください。VS Codeの場合なら
実行 > デバッグの再起動で再起動できます。
Step 3:Statefulウィジェットを作ってみる
Flutterには Stateless ウィジェットと Stateful ウィジェットがあります。
Statelessウィジェットは状態が変化しない(イミュータブルな)ウィジェットです。
反対にStatefulウィジェットは状態が変化しうる(ミュータブルな)ウィジェットです。ウィジェットが生まれてから破棄されるまでの間に、保持している値が変化する可能性があります。
Statefulウィジェットを実装するためには StatefulWidget と State という2つのクラスが必要になります。
-
StatefulWidgetクラスがStateクラスのインスタンスを作る -
StatefulWidgetクラスそのものはイミュータブルだが -
Stateクラスが対応するウィジェットの状態を保持する
という関係です。
ここでは、 RandomWords というStatefulウィジェットを作ってみます。 RandomWords ウィジェットは _RandomWordsState というStateクラスを作成します。最終的には、 MyApp Statelessウィジェットの子要素として RandomWords ウィジェットを持たせる形になります。
まず、 lib/main.dart の末尾に以下のコードを追記して、2つのクラスを定義します。
class RandomWords extends StatefulWidget {
@override
_RandomWordsState createState() => _RandomWordsState();
}
class _RandomWordsState extends State<RandomWords> {
@override
Widget build(BuildContext context) {
final wordPair = WordPair.random();
return Text(wordPair.asPascalCase);
}
}
_RandomWordsState クラスのクラス名の先頭の _ は、Dart言語における private アクセス修飾子です。名前の先頭に _ をつけることでこのクラスは private になります。
また、 _RandomWordsState クラスが State<RandomWords> を継承している点にも注目です。「 RandomWords クラス用として使われる State クラスである」ということを明示しています。
最後に、こうして定義した RandomWords ウィジェットを、 MyApp クラスで使うようにコードを修正します。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final wordPair = WordPair.random();
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
- child: Text(wordPair.asPascalCase),
+ child: RandomWords(),
),
),
);
}
}
アプリを再起動するなどしても、先ほどまでと同じような動作(ホットリロードする度に毎回ランダムな文字列が表示される)になっていればOKです👍
Step 4: 無限スクロールできるListViewを作ってみる
_RandomWordsState を、ランダムな単語ペアの リスト を生成するようなクラスに改造してみましょう。
ListView ウィジェットを使い、その builder() ファクトリが遅延的に実行される性質を生かして、無限にスクロールできるものにしていきます。
まず、 _RandomWordsState クラスに以下の2つの final (変更不可) なクラス変数を追加します。
class _RandomWordsState extends State<RandomWords> {
+ final _suggestions = <WordPair>[];
+ final _biggerFont = TextStyle(fontSize: 18.0);
+
@override
Widget build(BuildContext context) {
final wordPair = WordPair.random();
return Text(wordPair.asPascalCase);
}
_suggestions は提示する単語ペアのリスト( ListView ではなく情報としてのリスト)を保持する変数、 _biggerFont はあとでテキストのフォントサイズを大きくするときに使うための単なるスタイルの定義です。
次に、同じく _RandomWordsState クラスに、 ListView ウィジェットを組み立てるための _buildSuggestions() メソッドを作ります。
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]);
}
);
}
コードの解説は以下のとおりです。
-
/*1*/:itemBuilderに渡すコールバックは、各単語ペアごとに呼び出されて、その単語ペアを_buildRow()メソッド(まだこの時点では定義していない)に渡すことでListTileウィジェット(リストの1行を表すウィジェット)を生成する。ただし、偶数行目ではListTileを返すが、奇数行目では何もせずDividerウィジェットを 返す点に注意 -
/*2*/:Dividerウィジェットで高さ1ピクセルの仕切り線を作成(各行の間に仕切りを入れて見やすくするためだけ) -
/*3*/:i ~/ 2という式は、「2で割った結果を小数点以下切り捨てて整数にする」という演算をする。例えば、1, 2, 3, 4, 5が、この演算を通すことで0, 1, 1, 2, 2になる。この計算により、仕切り線の数を無視した実際の要素の数を算出している -
/*4*/:生成済みの単語ペアをすべて消費した場合に、さらに10個の単語ペアを追加で生成してリスト(ListViewではなく情報としてのリスト)に追加している
さらに、先ほどの _buildSuggestions() メソッドから単語ペアを受け取ってリストの1行を ListTile ウィジェットとして生成する _buildRow() メソッドを実装します。
Widget _buildRow(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
);
}
これでパーツは整ったので、実際に _RandomWordsState クラスの build() メソッドでこれらの処理を実行して ListView を作れるようにします。
@override
Widget build(BuildContext context) {
- final wordPair = WordPair.random();
- return Text(wordPair.asPascalCase);
+ return Scaffold(
+ appBar: AppBar(
+ title: Text('Startup Name Generator'),
+ ),
+ body: _buildSuggestions(),
+ );
}
最後に、 MyApp ウィジェット自体の build() メソッドも更新して、 RandomWords ウィジェットをそのまま表示するようにすれば完了です。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
- title: 'Welcome to Flutter',
- home: Scaffold(
- appBar: AppBar(
- title: Text('Welcome to Flutter'),
- ),
- body: Center(
- child: RandomWords(),
- ),
- ),
+ title: 'Startup Name Generator',
+ home: RandomWords(),
);
}
}
実行すると下図のような感じで表示されます。

マウスでドラッグすればスクロールできるので、無限にスクロールできることを確認してみてください👍
Discussion