Flutter入門 | Stateクラスの利用、StatefulWidgetについて!!
今回の記事ではStatefulWidgetについて解説していきながら、ボタンを押したら動的に表示が変わるアプリを作っていきたいと思います!!
目次
StatefulWidgetについて
前回の記事で利用したStatelessWidgetはステートを持たないウィジェットです。
ステートとはアプリの状態を保持するための仕組みです。
つまり、ステートがないということは最初に表示された状態のまま何も変化しないということです。
ですが、実際のアプリでは動的に表示が変わるのが当たり前です。
こうした動的に表示が変わるアプリはStatelessWidgetでは作れなません。
なので今回解説していくStatefulWidgetを使います。
StatefulWidgetとState
StatefulWidgetというクラスは状態を扱う機能を持っています。
これはStateというクラスで用意されています。
整理すると以下の形で定義されます。
StatefulWidgetクラスの基本型
class ウィジェット extends StatefulWidget {
@override
State<ウィジェットクラス> createState() => ステートクラス();
}
Stateクラスの基本型
class ステートクラス extends State<ウィジェットクラス> {
…略…
@override
Widget build(BuildContext context) {
…略…
}
}
StatefulWidgetクラスはウィジェット部分(StatefulWidgetクラス)、ステート部分(Stateクラス)の二つの部分で構成されています。
ウィジェットクラス
ウィジェットクラスはStatefulWidgetクラスを継承して定義します。
このクラスにはcreateStateというメソッドを実装する必要があります。
これはステートを作成するためのもので、一般にはステートクラスのインスタンスを作成して返すだけのシンプルな処理を用意します。
ステートクラス
ステートクラスはStateクラスを継承して作成します。
このとき、ウィジェットクラスを<>で囲って指定しておきます。
これで指定したウィジェットクラスで使われるステートクラスが定義できます。
ステートクラスにはbuildというメソッドが用意されています。
これはステートを生成する際に呼び出され、ここでステートとして表示されるウィジェットを返します。
ウィジェットクラスのcreateStateでステートクラスのインスタンスが使われ、これによってステートクラスのbuildで生成されたウィジェットが、ウィジェットクラスの表示として画面に表示されるようになります。
buildは常に呼び出される
buildはインスタンス生成時に呼び出されるというように理解するのではなく、ステートを生成するためのStateクラスのメソッドで、ステートの値を変更したりするときにも呼び出され、新たな表示を作成しているものと理解しましょう。
つまり、StatefulWidgetというのはステートが更新されるたびに、buildで新たな表示内容を生成して画面に表示するクラスです。
ステートを操作する
では、実際にステートを操作するサンプルを実装していきましょう。
main.dartを以下のように書き換えてください。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
final title = 'Flutterサンプル';
final message = 'サンプル・メッセージ';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(title: this.title, message: this.message),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
final String message;
const MyHomePage({super.key, required this.title, required this.message});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Text(
widget.message,
style: TextStyle(fontSize: 32.0),
));
}
}
実行すると簡単なメッセージが表示されました。

これはステートを使って画面を表示させていますが、まだステートを操作する処理は何も用意していません。ただ、StatefulWidgetを使ったウィジェットがどういったものか、サンプルとして表示してみただけのものです。
ステートクラスとの連携
ここではMyHomePageというウィジェットクラスをStatefulWidgetクラスとして作成しています。
そして、_MyHomePageStateというステートクラスを用意し、ステートとして設定しています。
ステートの設定を行なっているcreateStateメソッドを見ると以下のようになっているのがわかります。
@override
State<MyHomePage> createState() => _MyHomePageState();
_MyHomePageStateインスタンスを作成し、返しています。
これで_MyHomePageStateクラスがステートとして扱われるようになります。
この_MyHomePageStateクラスでは、buildメソッドでScaffoldインスタンスを返しています。
このScaffoldでは、appBarとbodyにそれぞれAppBarとTextを指定しています。
これによりアプリケーションバーとテキストが表示された画面が作成されます。
StatelessWidgetからStatefulWidgetへ値を渡す
ここではもう一つ新しい処理を行なっています。
それはアプリケーションの土台となっているStatelessWidgetからStatefulWidgetへ値を渡すということです。
StatelessWidgetクラスであるMyAppクラスでは、以下の値が用意されています。
final title = 'Flutterサンプル';
final message = 'サンプル・メッセージ';
finalが指定されており、値が変更されないことがわかります。
StatelessWidgetでは、このように固定された値を使います。
これらの値をStatefulWidget側に渡して利用しています。
return MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(
title: this.title,
message: this.message
),
);
homeに設定するMyHomePageインスタンスを作成する際、titleとmessageという二つの値を用意し、それぞれthis.titleとthis.messageを指定しています。
先ほどのプロパティを引数に指定してMyHomePageインスタンスを作っているのです。
このMyHomePageクラスでは以下のようにコンストラクタが用意されています。
const MyHomePage({super.key, required this.title, required this.message});
このクラスでもやはり、titleとmessageというプロパティが用意されています。
引数で渡された値が、そのままthis.titleとthis.messageに代入されていることがわかります。
これでMyAppに用意された値が、そのままMyHomePageに渡されました。
MyHomePageから_MyHomePageStateへ
続いて、MyHomePageに保管したtitleとmessageを使って、ステートクラスである_MyHomePageStateインスタンスを作成するところを見ていきましょう。
buildでScaffoldインスタンスを作成している処理は以下のようになります。
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Text(
widget.message,
style: TextStyle(fontSize: 32.0),
)
);
Textの引数に、それぞれwidget.titleとwidget.messageを指定しています。
widgetはステートクラスに用意されているプロパティで、このステートが設定されているウィジェット(ここではMyHomePageクラス)のインスタンスが代入されています。
つまりwidget.titleとすることで、この_MyHomePageStateに組み込まれている、MyHomePageのtitleプロパティを取り出しているのです。
これでMyHomePageに用意された値が、_MyHomePageState内で使用できるようになりました。
FlotingActionButtonをタップする
StatefulWidgetの基本がわかったところで、実際に操作してステートを変更してみましょう。
先ほどのサンプルをさらに修正して、タップして表示を変更するサンプルを掲載します。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
final title = 'Flutterサンプル';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(title: this.title),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({super.key, required this.title});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _message = 'Hello';
void _setMessage() {
setState(() {
_message = 'タップしました!';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Text(
_message,
style: TextStyle(fontSize: 32.0),
),
floatingActionButton: FloatingActionButton(
onPressed: _setMessage,
tooltip: 'set message.',
child: Icon(Icons.star),
),
);
}
}
実行すると以下の画像のように表示されます。

ボタンをタップするとメッセージの表示が変更されました!!

ごく単純なものですが、ユーザーの操作でステートが変更される例として最低限なものは揃っています。
ステート更新とsetState
ステートの変更は、State継承クラス内にメソッドとして用意します。
ここでは、_setMessageというメソッドとして用意しています。
void _setMessage() {
setState(() {
_message = 'タップしました!';
});
}
このメソッドでは、setStateというメソッドを実行しています。
このsetStateは、ステートの更新をステートクラスに知らせる働きがあります。
このメソッドに、必要な変更処理を用意しておきます。
このsetStateの引数は関数になっています。この関数内で必要な処理を実行します。
今回のサンプルでは、引数の関数内で_messageプロパティを変更しています。
_MyHomePageStateクラスを見ると、buildで生成されるウィジェットでは、Textのテキストに_messageが指定されています。
_messageを変更することで、更新時にbuildが再実行され、Textの値が変わるようになっています。
FloatingActionButtonについて
この_setMessageは、_MyHomePageStateクラスのfloatingActionButtonという値で呼び出されています。
floatingActionButtonはフローティングアクションボタンを設定します。
フローティングアクションボタンとは、Androidアプリなどでよく見られる、丸いアイコンを表示したボタンのことです。
先ほどのサンプルで、右下に表示された★マークのアイコンがこれです。
このフローティングアクションボタンは、他のウィジェットの配置とは関係なく、常に決まった場所(画面の右下あたり)に表示されます。
フローティングアクションボタンは、FloatingActionButtonというクラスとして用意されています。
サンプルでは、floatingActionButtonは以下のような値が設定されています。
floatingActionButton: FloatingActionButton(
onPressed: _setMessage,
tooltip: 'set message.',
child: Icon(Icons.star),
),
FloatingActionButtonのインスタンスを作成する際には、さまざまな値を引数に用意しておくことができます。
ここでは以下のような値を用意してあります。
onPressed
ボタンをタップした時の処理を指定する。通常、割り当てるメソッド名を指定する。ここでは、_setMessageを指定している。
tooltip
ツールチップとして表示するテキストを指定する。
child
このウィジェット内に組み込まれているウィジェット類をまとめたもの。ここでは表示するアイコンをIconで用意してある。
FloatingActionButtonインスタンスを作成する際には、匿名クラスの要素として、これらの値を用意しておきます。
これらの中で重要なのは、onPressedです。
これはステート変更を行うメソッド名を指定します。
onPressedはイベント処理を設定するためのプロパティです。
ボタンをタップすると、onPressedというイベントが発生し、このイベント発生元のウィジェットにonPressedプロパティが用意されていれば、そこにあるメソッドを呼び出して実行します。
イベントはonPressedだけでなく、他にもさまざまな操作に応じたものが、各ウィジェットに用意されています。ウィジェットを操作したときに何かを行わせたいときは、このイベントを利用した処理を用意することが基本になります。
childでは、表示するアイコンをIconクラスとして作成し、設定しています。
Iconクラスは、名前の通りアイコンを扱うクラスです。このIconはインスタンス作成時、引数にIconsクラスの値を指定しています。Iconsクラスは、主なアイコンを示す値をプロパティとして用意してまとめたものです。このクラスの中で、使用したいアイコンの値を選んで利用します。
ここでは、Icons.starで★アイコンを表示させています。
FloatingActionButtonには、アイコンを表示するchildと、タップした時の処理を指定するonPressedの二つの値が最低でも必要です。この二つの値さえ用意すれば、比較的簡単に利用することができます。
複雑な値の利用
ここまでは、ごく単純なテキストを表示するだけでしたが、より複雑な値を扱うこともあります。
Dataというクラスを定義し、これを値として扱うサンプルを見ていきましょう。
ベースとなるMyAppクラスは全く同じなので省略し、MyHomePageクラス以降を掲載しておきます。
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({super.key, required this.title});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
//データ用クラス
class Data {
int _price;
String _name;
Data(this._name, this._price) : super();
@override
String toString() {
return _name + ':' + _price.toString() + '円';
}
}
class _MyHomePageState extends State<MyHomePage> {
//サンプルデータ
static final _data = [
Data('Apple', 200),
Data('Orange', 150),
Data('Peach', 300),
];
Data _item = _data[0];
void _setData() {
setState(() {
_item = (_data..shuffle()).first;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Text(
_item.toString(),
style: TextStyle(fontSize: 32.0),
),
floatingActionButton: FloatingActionButton(
onPressed: _setData,
tooltip: 'set message.',
child: Icon(Icons.star),
),
);
}
}
ここでは、_MyHomePageStateクラスにDataリストを保管する_dataプロパティを用意し、ボタンをタップするとDataをランダムに選んで画面に表示します。

Dataクラスについて
複数の値で構成されたデータを扱うクラスとして、Dataクラスを定義してあります。複雑な値を扱う場合、必要な情報をまとめたクラスとして定義して利用するのが一般的です。
class Data {
int _price;
String _name;
Data(this._name, this._price) : super();
@override
String toString() {
return _name + ':' + _price.toString() + '円';
}
}
Dataクラスでは、_nameと_priceという二つの値を用意しました。コンストラクタでは、引数の値をそれぞれのプロパティに設定できるようにしています。
またtoStringをオーバーライドし、内容をテキストにまとめて設定できるようにしています。
Dataインスタンスの設定
ステートクラス側では、Dataインスタンスをまとめたリストを作っておき、これをランダムに選んで表示させる処理をしています。まず最初にデータとなるリストと、選んだデータを保管するプロパティを用意していきます。
static final _data = [
Data('Apple', 200),
Data('Orange', 150),
Data('Peach', 300),
];
Data _item = _data[0];
Dataインスタンスを保管する_dataは、あとでデータを改変することがないため、static finalにしてあります。
そして、_dataの最初の項目を_itemに設定しています。
これで起動時に、最初のデータが表示されるようになります。あとは、ステートを設定する_setDataで、リストからランダムに選ぶ処理を用意するだけです。
void _setData() {
setState(() {
_item = (_data..shuffle()).first;
});
}
ここでは、setState内で(_data..shuffle()).firstという形で値を取り出しています。
shuffleはリストの項目をランダムに入れ替えるメソッドで、firstは最初の項目のプロパティです。これにより、_dataからランダムに値を一つだけ取り出せます。
まとめ
今回はステートを使って動的に値を変更することができる、StatefulWidgetについて解説していきました!!
いかがだったでしょうか。
実際に画面に表示するテキストが変わっていくのは見ていて面白いですよね!!
次回はFlutterのレイアウトの続きを公式ドキュメントを元に解説していきたいと思います。
良きFlutterライフを!!
2025-03-21
0件のコメント
コメントはまだありません。最初の一人になりましょう!