Flutterの画面に配置するWidgetは、まとまりごとにカスタムWidgetとして別クラスを作成することが多いです。
その際、別クラスと、その別クラスを呼び出している親となるクラスとは、何らかのデータのやり取りが必要になります。
このクラス間のデータのやり取りの仕方を、チェックボックス(Checkbox)、ボタン(ElevatedButton)を使って解説します。
*テキストフィールド(TextField)の例を、追加執筆中です。
- Flutter : 3.24.4
- Dart : 3.5.4
Dartのコード概要とスマホの完成画面
このアプリでは、チェックボックス・ボタン・それとテキストフィールド2つを、子Widgetとして配置し、それぞれの子Widgetで入力した結果を、親であるHomeScreenが受け取って画面表示します。

子Widget自身には、HomeScreenと値の受け渡しをするだけで、実行する内容は記述しません。
main.dartでは、引数なしでHomeScreen()を呼んでいます。

HomeScreen()はmain()のhome:で指定。このコードではまだ子Widgetのクラスが未作成なのでエラーになっています。
コードを書く手順
親Widget(HomeScreen)に大枠を記述
まずは、親となるHomeScreen()を作ります。
子Widgetのクラスを先に作ってもいいけれど、Flutterは小さい部品から作るよりも、大枠を先に作る方が考えやすいです。

CheckboxArea():チェックボックスを表示するElevatedButtonArea():ElevatedButtonを表示するTextFieldArea01():テキストフィールドを表示するTextFieldArea02():テキストフィールドを表示する
この時点では、子Widgetとして呼び出すクラスファイルがないので、赤いエラーが出ています。
子Widgetの作成
Checkbox:「受け取る値がある」とき
呼び出し元の親クラスHomeScreen()の大枠ができたので、別のDartファイルに子WidgetとしてCheckboxを作ります。
まずは、いつも通りのクラスの作成です。
return文でCheckboxを入れて、必須プロパティのvalue:とonChanged:を指定します。
このプロパティには、変数を指定します。

必須プロパティに指定した変数はfinalで宣言します。
その際の「型」は、Checkbox()の定義ファイルを見て調べます。
クラスの定義ファイルは、クラス名やプロパティ名の上で[F4]キーを押せば該当行へジャンプできます。
ジャンプ先で再度[F4]を押していくと、その先の定義箇所へどんどん深くジャンプしていきます。
この定義ファイルで確認して、valueはbool、onChangedにはValueChangedと明記しておきます。
![CheckBoxのonChangedオプションに指定する値の型を調べるには、[F4]キーで定義箇所にジャンプする。](https://fluttoco.com/wp-content/uploads/2024/12/child-to-parent0400-checkboxfile.jpg)
valueはbool、onChangedはbool値を扱うValueChangedということがわかる次に、ここで作った変数をコンストラクタ内に記述します。
このコンストラクタの変数を中継して、CheckboxArea()とHomeScreenがつながります。

HomeScreenとCheckboxAreaをつなぐ役割をするコンストラクタに値を中継する変数を入れたら、CheckboxArea()クラスが完成です。
import 'package:flutter/material.dart';
class CheckboxArea extends StatelessWidget {
const CheckboxArea({super.key, required this.checked, required this.onChanged});
final bool checked;
final ValueChanged onChanged;
@override
Widget build(BuildContext context) {
return Checkbox(
value: checked,
onChanged: onChanged,
);
}
}ElevatedButton:受け取る「値がない」とき
次に、ElevatedButtonArea()を作ります。
ElevatedButtonの必須プロパティは、child:とonPressed:です。
child:は、ボタンに表示する文字です。
onPressed:には、このボタンが押されたときの処理を変数として指定します。
ここではonPressedという変数名にしました。
この変数もCheckboxのonChanged:のときと同じように、finalで変数宣言します。
ElevatedButtonのonPressed:の型も、[F4]を押して調べて入れておきます。VoidCallbackです。

import 'package:flutter/material.dart';
class ElevatedButtonArea extends StatelessWidget {
const ElevatedButtonArea({super.key, required this.onPressed});
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: const Text('ElevatedButton'),
);
}
}ElevatedButtonの場合は、Checkboxのようにon/off(true/false)などの値を持ちません。
親WidgetのHomeScreen()は、「ボタンが押された」ということを受け取るだけです。
ValueChangedもVoidCallbackも、中身はFunctionですが、この「値を持つ」「値を持たない」という点が、CheckboxArea()ではValueChangedを使い、ElevatedButtonArea()ではVoidCallbackを使う、という違いです。
![「ValueChanged」「VoidCallback」にカーソルを当て[F4]を押して、その型の定義にジャンプする。](https://fluttoco.com/wp-content/uploads/2024/12/child-to-parent1000-valuechanged-voidcallback.jpg)
ValueChangedは「引数ありのFunction()」VoidCallbackは「引数なしのFunction()」親Widget(HomeScreen)に値の受け渡し処理を記述
子WidgetのCheckboxArea()とElevatedButtonArea()が完成したので、HomeScreen()で値の受け渡しを書きます。
Checkbox
まずはimportで、checkbox_area.dartをインポートしておきます。
そして、CheckboxArea()のコンストラクタに作成したcheckedとonChangedの設定です。
checked:には、ここでも変数を指定します。true/falseを、そのまま書いてはいけません。
変数名は「画面に表示する値」という意味でviewCheckValueという名前にしました。
このviewCheckValueの型は、CheckboxArea()で指定したのと同じbool。
初期値はfalseとしています。
onChangedには、Checkboxの値が変わったときの処理を書きます。

onChangedには、処理内容を書く Text(' Checkbox : $viewCheckValue'),
CheckboxArea(
checked: viewCheckValue,
// ↓value: CheckboxArea()から返された値
onChanged: (value) {
// viewCheckValueに戻り値を代入して再描画
setState(() {
viewCheckValue = value;
});
},
),ここでのonChangedの役割は、CheckboxArea()で値が変わったら、その値に応じて画面表示を更新することです。
画面の再描画はsetStateを実行すればいいので、CheckboxArea()から受け取った値をviewCheckValueに代入する操作をsetStateの中に書きます。
Checkboxに変更があったらsetStateが実行され、checked: viewCheckValue,の値でCheckboxArea()が再度呼び出されて再描画されるというわけです。
これで、CheckboxArea()から値を受け取ることができるようになりました。
ElevatedButton
次はElevatedButtonArea()です。
まずは、elevated_button_area.dartをインポートします。
そして、ElevatedButtonArea()のコンストラクタに作成したonPressedに、ElevatedButtonが押されときの処理を記述します。
処理内容は、「画面表示の数字をカウントアップして再描画(setState)する」です。
ElevatedButtonArea()のonPressedはVoidCallbackなので、値の受け渡しがありません。
受け取る値がないので、setStateの( )の中にも変数は書きません。
ボタンが押されるたびにカウントアップして画面表示する必要があるので、カウントアップ計算用にint countを宣言して、Text()ウィジェットを追加しました。

onPressedで、変数をカウントアップして画面の再描画を実行 Text(count.toString()),
ElevatedButtonArea(
onPressed: () {
setState(() {
count++;
});
},
),これで、ElevatedButtonArea()とHomeScreen()がつながりました。
完成Dartファイル
下記が、作成したDartファイルです。
前述のWidgetだけではスマホ画面が見にくいので、文字体裁など少し装飾する設定を追加してあります。
未解説のテキストフィールド部分も入っています。
子クラスは、前述の項目「checkbox_area.dart」「elevated_button_area.dart」を見てください。
HomeScreen()
import 'package:flutter/material.dart';
import 'components/checkbox_area.dart';
import 'components/elevated_button_area.dart';
import 'components/text_field_area01.dart';
import 'components/text_field_area02.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<HomeScreen> {
bool viewCheckValue = false;
int count = 0;
String viewText01 = '入力前';
String viewText02 = '入力前';
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 56.0),
Text(' Checkbox : $viewCheckValue',
style: const TextStyle(fontSize: 16.0)),
CheckboxArea(
checked: viewCheckValue,
onChanged: (value) {
setState(() {
viewCheckValue = value;
});
},
),
//
const SizedBox(height: 16.0),
Text(' ElevatedButton: $count',
style: const TextStyle(fontSize: 16.0)),
ElevatedButtonArea(
onPressed: () {
setState(() {
count++;
});
},
),
//
const SizedBox(height: 32.0),
Text(
' TextField 01 : $viewText01',
style: const TextStyle(fontSize: 18.0),
),
const Text(' (子Widgetで「メソッド渡し」で記述)'),
TextFieldArea01(
onSubmitted: (inputtedText) {
setState(() {
viewText01 = inputtedText;
});
},
),
const SizedBox(height: 16.0),
Text(
' TextField 02 : $viewText02',
style: const TextStyle(fontSize: 18.0),
),
const Text(' (子Widgetで、引数付きで記述)'),
TextFieldArea02(
onSubmitted: (inputtedText) => updateText02(inputtedText),
),
],
),
);
}
// TextFieldArea02()で実行する関数
updateText02(String inputtedText) {
setState(() {
viewText02 = inputtedText;
});
}
}main()
import 'package:flutter/material.dart';
import 'screens/home_screen.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'ValueChanged Try',
home: HomeScreen(),
);
}
}

コメント