ボタンのタップに反応し、setStateで表示を更新して、画面に命を吹き込みましょう。
このレッスンを Kodokon で開く私たちの画面はきれいですが、固まっています。ユーザーの操作に反応するときが来ました。標準的なMaterial 3のボタンはElevatedButtonです。二つの欠かせないパラメーターを取ります。childは表示される中身(多くはText)で、onPressedはタップしたときに実行する関数です。このようにパラメーターとして渡される関数はコールバックと呼ばれます。あなた自身がそれを呼ぶのではなく、Flutterが適切なタイミングで代わりに呼んでくれます。() { ... }という構文は、名前のない無名関数を、その場に直接書いて作ります。
import 'package:flutter/material.dart';
Widget buildHelloButton() {
return ElevatedButton(
onPressed: () {
debugPrint("Button pressed!");
},
child: const Text("Tap here"),
);
}debugPrintはコンソールに書き込みます……が、画面そのものは変わりません。なぜでしょう? それは、StatelessWidget(状態を持たないウィジェット)が固まっているからです。一度作られると、もう変われません。変化する値を表示するには、StatefulWidget(状態を持つウィジェット)が必要です。状態とは、ウィジェットの一生の間に変わりうるデータの集まりです。カウンター、チェックされた箱、入力されたテキストなど……。StatefulWidgetは常にStateクラスと一対で、このクラスがそのデータを保持し、buildメソッドを含みます。これが初期からの大定番、カウンターです。
import 'package:flutter/material.dart';
void main() {
runApp(const CounterApp());
}
class CounterApp extends StatelessWidget {
const CounterApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(useMaterial3: true),
home: const CounterPage(),
);
}
}
class CounterPage extends StatefulWidget {
const CounterPage({super.key});
@override
State<CounterPage> createState() =>
_CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Counter: $count",
style: const TextStyle(fontSize: 32),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
setState(() {
count = count + 1;
});
},
child: const Text("+1"),
),
],
),
),
);
}
}しくみは三つのステップで成り立ちます。1) count変数は_CounterPageStateの中にあります。それが状態です。2) タップするたびに、コールバックがsetStateを呼びます。このメソッドは状態を変更し、そして何かが変わったことをFlutterに伝えます。3) するとFlutterはbuildをもう一度実行し、countの新しい値で画面を描き直します。この考え方を覚えておきましょう。画面を直接変えることは決してなく、データを変えて、表示はFlutterに任せるのです。