TEXTBOOK SECTION / AI LEARNING

StatefulWidgetで画面状態を扱う

Flutterアプリケーション開発概論の「3Dモデルと描画」より、StatefulWidgetで画面状態を扱うを解説。生成AI、AI活用、DX、業務改善を実践しながら学べるオンライン教材です。

103Dモデルと描画Flutter / iOS / Android / MacOS / Windows / 基礎から学ぶ / 開発 / アプリ開発

OVERVIEW

この節で学べること

概要を表示する
項目内容
教材名Flutterアプリケーション開発概論
3Dモデルと描画
StatefulWidgetで画面状態を扱う
カテゴリFlutter / iOS / Android / MacOS / Windows / 基礎から学ぶ / 開発 / アプリ開発
学習内容生成AI、AI活用、DX、業務改善を実践しながら理解するための教材です。

TABLE OF CONTENTS

目次

CONTENT

ここから

この章では、StatefulWidgetが画面の状態をどのように保持し、変更内容を画面へ反映するのかを整理します。

第8章ですでにModelViewerScreenStatefulWidgetへ変更しましたが、現時点では3Dコントローラーを保持する目的が中心でした。今後は、モデルの読み込み中、表示完了、エラー発生といった状態も管理します。

10.1 StatelessWidgetとの違い

StatelessWidgetは、表示中に変化する値を内部へ保持しないWidgetです。タイトルや固定された説明文など、同じ内容を表示し続ける部品に適しています。

一方、StatefulWidgetは、操作や処理の結果によって画面が変わる場合に使用します。

今回のアプリでは、次のような変化を扱います。

  • モデルの読み込みが完了する
  • 読み込み中の案内を消す
  • エラーメッセージを表示する
  • 再読み込みによって状態を初期化する
  • モデル表示後にリセットボタンを有効にする

これらは実行中に変化するため、StatefulWidgetが必要です。

10.2 StatefulWidgetとStateの関係

StatefulWidgetは、Widgetの設定を表します。実際に変化する値は、対応するStateクラスへ保持します。

class ModelViewerScreen extends StatefulWidget {
  const ModelViewerScreen({super.key});

  @override
  State<ModelViewerScreen> createState() {
    return _ModelViewerScreenState();
  }
}

createState()は、Widgetに対応する状態オブジェクトを生成します。

class _ModelViewerScreenState extends State<ModelViewerScreen> {
  final Flutter3DController _controller = Flutter3DController();

  @override
  Widget build(BuildContext context) {
    // 画面を構築する
  }
}

ModelViewerScreen自体の設定は変更せず、コントローラーや読み込み状態などは_ModelViewerScreenStateへ置きます。

10.3 状態を保持する変数

状態として管理する値は、Stateクラスのフィールドとして定義します。

たとえば、モデルの読み込みが完了しているかを真偽値で表す場合は、次のように記述できます。

bool _isModelReady = false;

エラー内容を保持する場合は、文字列を使用できます。

String _errorMessage = '';

ただし、読み込み中、完了、エラーという3種類の状態を複数の真偽値で管理すると、矛盾した状態が生まれる可能性があります。

読み込み中であり、同時に完了している
完了しているが、エラーも発生している

この問題を避けるため、次章ではenumを使って状態を一つの値として管理します。

10.4 setState()で画面を更新する

状態変数へ新しい値を代入しただけでは、画面は自動的に更新されません。変更を画面へ反映するには、setState()を使用します。

void _markModelReady() {
  setState(() {
    _isModelReady = true;
  });
}

setState()の中で状態を変更すると、Flutterは該当するStatebuild()を再実行します。

次のように、setState()の外側で値だけを変更した場合、内部の値は変わっても画面表示が更新されない可能性があります。

void _markModelReady() {
  _isModelReady = true;
}

画面表示に関係する値を変更するときは、原則としてsetState()を使用します。

10.5 Widgetが再構築される仕組み

setState()を実行すると、Flutterはbuild()を再度呼び出し、現在の状態をもとにWidgetを作り直します。

@override
Widget build(BuildContext context) {
  return Text(
    _isModelReady ? '表示完了' : '読み込み中',
  );
}

_isModelReadyfalseなら「読み込み中」、trueなら「表示完了」が返されます。

再構築とは、画面全体を最初から描画し直すことではありません。Flutterは変更前後のWidgetを比較し、必要な部分だけを効率的に更新します。

そのため、build()の中には、通信処理やファイル保存などの重い処理を書かず、現在の状態から表示するWidgetを決める処理を記述します。

10.6 状態変更処理をメソッドへ分ける

状態変更をbuild()へ直接書き込むのではなく、役割ごとのメソッドへ分けます。

/// モデル読み込み完了後の状態を反映します。
///
/// 入力: なし
/// 出力: なし
void _handleModelLoaded() {
  setState(() {
    _isModelReady = true;
    _errorMessage = '';
  });
}

処理をメソッドへ分けると、次の点が明確になります。

  • いつ状態が変わるのか
  • どの値を変更するのか
  • 何のイベントに対応する処理なのか

後の章では、読み込み完了、エラー、再読み込みをそれぞれ別のメソッドとして実装します。

10.7 mountedを確認する理由

3Dモデルの読み込みは、開始してから完了するまでに時間がかかります。その間に利用者が別画面へ移動すると、読み込み完了時点で元の画面が破棄されている可能性があります。

mountedは、現在のStateがまだWidgetツリーに存在しているかを表します。

void _handleModelLoaded() {
  if (!mounted) {
    return;
  }

  setState(() {
    _isModelReady = true;
  });
}

破棄された画面に対してsetState()を実行すると、実行時エラーの原因になります。時間のかかる処理やコールバックの後で画面を更新する場合は、mountedを確認します。

10.8 build()内で状態を変更しない

build()は、状態をもとに画面を作るためのメソッドです。原則として、build()の実行中にsetState()を呼び出してはいけません。

@override
Widget build(BuildContext context) {
  // build中に状態を変更しない
  setState(() {
    _isModelReady = true;
  });

  return const SizedBox();
}

このような処理は、再構築中に再び再構築を要求し、エラーや不要な繰り返し処理につながります。

状態は、ボタン操作、読み込み完了、通信結果などのイベントを受け取ったタイミングで更新します。

10.9 この章の到達目標

この章の終了時点で、次の内容を確認します。

  • StatelessWidgetStatefulWidgetの違いを説明できる
  • 変化する値をStateクラスへ保持できる
  • setState()が必要な理由を説明できる
  • 状態変更後にbuild()が再実行されることを理解している
  • 状態変更処理をメソッドへ分離できる
  • 非同期処理後にmountedを確認する理由を説明できる
  • build()内で状態を変更してはいけない理由を理解している

この章では、状態管理の仕組みを確認したため、画面の見た目にはまだ大きな変更がありません。

次章では、読み込み中、表示完了、エラーを表すViewerStatusを定義し、3Dビューアーの状態を安全に管理します。

https://app.notion.com/p/39fb4ab5d13680e1a129e6b2b0c087cb?v=2c7b4ab5d136802d9a64000c46ee24e8&source=copy_link

FAQ

よくある質問

StatefulWidgetで画面状態を扱うは医療関係者向けだけの内容ですか。
医療分野の例が含まれる場合もありますが、医療関係者だけに限定した内容ではありません。生成AI、AI活用、DX、業務改善、プロトタイプ開発など、一般的なAI学習の事例として読める内容です。
AI初心者でも読めますか。
はい。AIをこれから学ぶ方、数学が苦手な方、仕事でAIを使いたい方にも読み進めやすいように、教材の章と節の流れに沿って整理しています。
サムネイル画像は必ず表示されますか。
はい。教材にcoverUrlが設定されている場合はその画像を表示し、未設定の場合は代替サムネイル画像を表示します。
Flutterアプリケーション開発概論のほかの章も読めますか。
はい。教材トップから章立てを確認でき、前後の節へもページ下部のナビゲーションから移動できます。