ウィジェット学習メモの状態

        ウィジェットには、StatelessWidget と StatefulWidget の 2 種類があります。StatefulWidget は視覚効果の動的な変更を必要とするインタラクティブなシーン用であり、StatelessWidget は静的でステートレスなビュー表示用です。StatefulWidget のシーンは完全に StatelessWidget をカバーしているので、インターフェースを構築する際に、静的ビューの表示要件に対応するために StatefulWidget を多用することが多く、問題はないようです。

UI プログラミング パラダイム

        StatelessWidget と StatefulWidget の使用シナリオを理解するには、まず、Flutter でウィジェット (ウィジェット) の表示スタイルを調整する方法、つまり UI プログラミング パラダイムを理解する必要があります。

        ネイティブ システム (Android、iOS) またはネイティブ JavaScript 開発の経験がある場合は、ビューの開発が不可欠であり、オペレーティング システムまたはブラウザーに操作方法を正確に伝える必要があることを知っておく必要があります。たとえば、インターフェイスのコピーを変更する場合は、特定のテキスト コントロールを見つけて、そのコントロール メソッド コマンドを呼び出して、テキストの変更を完了する必要があります。

        次のコードは、Android、iOS、ネイティブ Javascript でテキスト コントロールのテキストを Hello World に変更する方法を示しています。

        


// Android设置某文本控件展示文案为Hello World
TextView textView = (TextView) findViewById(R.id.txt);
textView.setText("Hello World");

// iOS设置某文本控件展示文案为Hello World
UILabel *label = (UILabel *)[self.view viewWithTag:1234];
label.text = @"Hello World";

// 原生JavaScript设置某文本控件展示文案为Hello World
document.querySelector("#demo").innerHTML = "Hello World!";

違いは、Flutter のビューの開発は宣言型であり、その中心的な設計思想はビューとデータを分離することであり、これは React の設計思想とまったく同じです。   

同じ要件を達成したい場合は、もう少し面倒です。Widget レイアウト スキームを設計することに加えて、事前にコピー データ セットを維持し、Widget のデータ セット内のデータをバインドする必要があります。ウィジェットがこのデータに基づくことができるように、変更する必要があります。セットがレンダリングされます。

ただし、インターフェイスのコピーライティングを変更する必要がある場合は、データ セット内のコピーライティング データを変更し、Flutter フレームワークに通知してウィジェットの再レンダリングをトリガーするだけです。このように、開発者は、データ セットが維持されている限り、UI プログラミングの各プロセスの詳細に注意を払う必要がなくなります。さまざまなコンポーネント (ウィジェット) の視覚的なプロパティを 1 つずつ設定する必要がある命令型のビュー開発方法と比較して、この方法ははるかに便利です。

ウィジェットの紹介

(ウィジェットの紹介 | Flutter )

        Flutter ウィジェットは、React からインスピレーションを得た最新のフレームワークを使用して構築されています。中心的な考え方は、ウィジェットを使用して UI を構築することです。ウィジェットは、現在の構成と状態を考慮して、ビューがどのように見えるべきかを記述します。ウィジェットの状態が変化すると、ウィジェットはその説明を再構築し、フレームワークはそれを以前の説明と比較して、基になるレンダリング ツリーがある状態から別の状態に遷移するために必要な最小限の変更を決定します。

        最小限の Flutter アプリでは、runApp() 関数を呼び出すウィジェットを使用するだけです。

        

import 'package:flutter/material.dart';

void main() {
  runApp(const Center(
    child: Text(
      'Hello World',
      textDirection: TextDirection.ltr,
    ),
  ));
}

         runApp() 関数は、特定の Widget を受け取り、それを Widget ツリーのルートにします。この例では、ウィジェット ツリーは、中央のウィジェットとその子テキスト ウィジェットの 2 つのウィジェットで構成されています。フレームワークは、ルート ウィジェットが画面を覆うように強制します。つまり、「Hello, world」というテキストが画面の中央に配置されます。この場合、テキストの方向を指定する必要があります。これは、以下に示すように、MaterialApp ウィジェットを使用するときに処理されます。

        アプリケーションを作成するときは、通常、ウィジェットが状態を管理するかどうかに応じて、StatelessWidget または StatefulWidget のサブクラスである新しいウィジェットを作成します。ウィジェットの主な仕事は build() 関数を実装することです。この関数は、他の下位レベルのウィジェットに関してウィジェットを記述します。フレームワークは、ウィジェットのジオメトリを計算して記述する、基礎となる RenderObject を表すウィジェットでプロセスが底をつくまで、これらのウィジェットを順番に構築します。

基本的な ウィジェット ウィジェットの紹介 | フラッター

Flutter には、次のような強力な基本ウィジェットのセットが付属しています。

文章

テキスト ウィジェットを使用すると、アプリケーションで一連のスタイル付きテキストを作成できます。Text クラス - ウィジェット ライブラリ - Dart API (flutter.dev)

単一のスタイルを持つテキストの範囲。テキスト ウィジェットは、1 つのスタイルでテキストの文字列を表示します。レイアウトの制約によっては、文字列が複数の行にまたがって表示される場合や、すべてが同じ行に表示される場合があります。

スタイル パラメータはオプションです。省略した場合、テキストは最も近い DefaultTextStyle を囲むスタイルを使用します。指定されたスタイルの TextStyle.inherit プロパティが true (デフォルト) の場合、指定されたスタイルは最も近い DefaultTextStyle にマージされます。このマージ動作は、たとえば、デフォルトのフォント ファミリとサイズを使用するときにテキストを太字にする場合に役立ちます。

この例では、オーバーフローが TextOverflow.ellipsis に設定されたテキスト ウィジェットを使用してテキストを表示する方法を示します。

import 'package:flutter/material.dart';

void main() {
  runApp(const Center(
    child: Text(
      'Hello, David! How are you?',
      textAlign: TextAlign.center,
      overflow: TextOverflow.ellipsis,
      textDirection: TextDirection.ltr,
      style: TextStyle(fontWeight: FontWeight.bold),
    ),
  ));
}

import 'package:flutter/material.dart';

void main() {
  runApp(const Center(
    child: Text(
      'Hello, David! How are you How are you How are you How are you How are you How are you How are you?',
      textAlign: TextAlign.center,
      overflow: TextOverflow.ellipsis,
      textDirection: TextDirection.ltr,
      style: TextStyle(fontWeight: FontWeight.bold),
    ),
  ));
}

 Text.rich コンストラクターを使用して、Text ウィジェットはさまざまなスタイルの TextSpans で段落を表示できます。以下の例は、「Hello beautiful world」を単語ごとに異なるスタイルで表示しています。

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const RichTextDemo(),
    );
  }
}

class RichTextDemo extends StatelessWidget {
  const RichTextDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      child: const Text.rich(
        TextSpan(
            text: 'Hello\n',
            style: TextStyle(fontWeight: FontWeight.normal),
            children: <TextSpan>[
              TextSpan(
                  text: 'beautiful\n',
                  style: TextStyle(fontStyle: FontStyle.italic)),
              TextSpan(
                  text: 'world', style: TextStyle(fontWeight: FontWeight.bold))
            ]),
      ),
    );
  }
}

 対話性

Text をタッチ イベントに反応させるには、GestureDetector.onTap ハンドラーを使用して GestureDetector ウィジェットにラップします。

マテリアル デザイン アプリケーションでは、代わりに TextButton を使用することを検討してください。それが適切でない場合は、少なくとも GestureDetector の代わりに InkWell を使用してください。

テキストの一部をインタラクティブにするには、RichText を使用し、TapGestureRecognizer をテキストの関連部分の TextSpan.recognizer として指定します。

選ぶ

テキストはデフォルトでは選択できません。テキストを選択可能にするために、SelectionArea ウィジェットでサブツリーをラップできます。SelectionArea の下のサブツリーの一部を選択から除外するには、サブツリーのその部分も SelectionContainer.disabled でラップします。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(_title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: const <Widget>[
              Text('Selectable text'),
              SelectionContainer.disabled(child: Text('Non-selectable text')),
              Text('Selectable text'),
            ],
          ),
        ),
      ),
    );
  }
}

 

RichText。これにより、テキスト スタイルをより詳細に制御できます。

テキスト ウィジェットのデフォルト スタイルを設定する DefaultTextStyle。

選択システムの概要を提供する SelectableRegion。

行、列

Flutter レイアウトの基本概念 | フラッター

これらのフレックス ウィジェットを使用すると、水平 (行) 方向と垂直 (列) 方向の両方で柔軟なレイアウトを作成できます。これらのオブジェクトの設計は、Web のフレックスボックス レイアウト モデルに基づいています。

行クラス

子を水平配列で表示するウィジェット。

子ビューを拡張して使用可能な水平スペースを埋めるには、子ビューを Expanded ウィジェットでラップします。

Row ウィジェットはスクロールしません (また、使用可能な部屋に収容できるよりも多くの子が Row にあると考えるのは一般的に間違っています)。ウィジェットの行があり、スペースがなくなったときにウィジェットをスクロールできるようにする場合は、ListView の使用を検討してください。

垂直バリアントについては、列を参照してください。

子が 1 つしかない場合は、"align" または "center" を使用して子を配置することを検討してください。

Row と Column は、ウィジェットを格納して配置するクラスです。行または列内のウィジェットは子と呼ばれ、行と列は親と呼ばれます。Row はウィジェットを水平にレイアウトし、Column はウィジェットを垂直にレイアウトします。

次の例は、行と列の違いを示しています。

1. [実行] ボタンをクリックします。

2. コードで、Row を Column に変更し、再度実行します。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyWidget());
}

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(_title),
        ),
        body: Row(
          children: const [BlueBox(), BlueBox(), BlueBox()],
        ),
      ),
    );
  }
}

class BlueBox extends StatelessWidget {
  const BlueBox({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(color: Colors.blue, border: Border.all()),
    );
  }
}

 

 軸のサイズと配置

これまでのところ、BlueBox ウィジェットはまとめられています (UI 出力の左側または上部)。BlueBox ウィジェットの配置方法は、軸のサイズと配置のプロパティを使用して変更できます。

mainAxisSize プロパティ

行と列は異なる主軸を占めます。行の主軸は水平で、列の主軸は垂直です。mainAxisSize プロパティは、Row と Column がその主軸上で占有できるスペースの量を決定します。mainAxisSize プロパティには、次の 2 つの値があります。

MainAxisSize.max

行と列は、主軸上のすべてのスペースを占有します。子の合計幅が主軸の合計スペースより小さい場合、子は追加のスペースで配置されます。

MainAxisSize.min

行と列は、子の主軸上で十分なスペースしか占有しません。それらの子は、余分なスペースなしで主軸の中央に配置されます。

ヒント: MainAxisSize.max は、mainAxisSize プロパティのデフォルト値です。他の値が指定されていない場合、上記の例のようにデフォルト値が使用されます。

例: 軸サイズの変更

次の例では、明示的に mainAxisSize をデフォルト値の MainAxisSize.max に設定します。

1. [実行] ボタンをクリックします。

2. MainAxisSize.max を MainAxisSize.min に変更して、再度実行します。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyWidget());
}

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(_title),
        ),
        body: Row(
          mainAxisSize: MainAxisSize.min,
          children: const [BlueBox(), BlueBox(), BlueBox()],
        ),
      ),
    );
  }
}

class BlueBox extends StatelessWidget {
  const BlueBox({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(color: Colors.blue, border: Border.all()),
    );
  }
}

 

mainAxisAlignment プロパティ

mainAxisSize が MainAxisSize.max に設定されている場合、Row と Column は子のために余分なスペースをレイアウトすることがあります。mainAxisAlignment プロパティは、Row と Column が余分なスペースに子を配置する方法を決定します。mainAxisAlignment には 6 つの可能な値があります。

MainAxisAlignment.start

主軸の始点近くに子を配置します。( は左 Row、 は上 Column)

MainAxisAlignment.end

主軸の端近くに子を配置します。(右が Row、下が Column)

MainAxisAlignment.center

子を主軸の中央に配置します。

MainAxisAlignment.spaceBetween

余分なスペースを子供たちの間で均等に分けます。

MainAxisAlignment.spaceEvenly

余分なスペースを子の間、および子の前後に均等に分配します。

MainAxisAlignment.spaceAround

MainAxisAlignment.spaceEvenly と似ていますが、最初の子の前と最後の子の後のスペースの半分を子の間の幅の半分に減らします。

要約すると、命令型プログラミングはプロセスの詳細を正確に制御することを強調し、宣言型プログラミングは意図による結果の全体的な出力を強調します。Flutter に対応して、意図はコンポーネントの状態の状態をバインドすることであり、結果は再レンダリングされたコンポーネントです。Widget の有効期間中、State に変更が適用されると、Widget は強制的に再構築されます。

その中で、作成後にコンポーネントを変更する必要がないシナリオでは、状態バインディングはオプションです。ここで、「オプション」は 2 つのタイプのウィジェット、つまりバインディング状態のない StatelessWidget とバインディング状態の StatefulWidget を区別します。構築したいユーザー インターフェイスがどの状態情報でも変わらない場合は、StatelessWidget を使用することを選択する必要があります。それ以外の場合は、StatefulWidget を選択する必要があります。前者は一般に静的コンテンツの表示に使用され、後者はインタラクティブなフィードバックを伴うコンテンツの表示に使用されます。

次に、StatelessWidget と StatefulWidget を紹介し、ソース コードとの違いを分析し、ウィジェットの選択に関するいくつかの基本原則をまとめます。

ステートレスウィジェット

Flutter では、ウィジェットは親から子へ、トップダウン方式で構築されます. 親ウィジェットは子ウィジェットの表示スタイルを制御し、そのスタイル構成は構築中に親ウィジェットによって提供されます.

この方法で構築された一部のウィジェット (テキスト、コンテナー、行、列など) は、作成時にこれらの構成パラメーター以外の情報に依存しません。が正常に作成され、データの変更に応じて再描画されません。Flutter では、このような Widget を StatelessWidget (ステートレス コンポーネント) と呼びます。

以下は、StatelessWidget の図です。

 

次に、Text のソース コードの一部を例に、StatelessWidget の構築プロセスを説明します。


class Text extends StatelessWidget {     
  //构造方法及属性声明部分
  const Text(this.data, {
    Key key,
    this.textAlign,
    this.textDirection,
    //其他参数
    ...
  }) : assert(data != null),
     textSpan = null,
     super(key: key);
     
  final String data;
  final TextAlign textAlign;
  final TextDirection textDirection;
  //其他属性
  ...
  
  @override
  Widget build(BuildContext context) {
    ...
    Widget result = RichText(
       //初始化配置
       ...
      )
    );
    ...
    return result;
  }
}

 構築メソッドがそのプロパティ リストを割り当てた後、build メソッドはすぐにそのプロパティ リスト (テキスト データ、配置メソッド textAlign、テキスト表示方向 textDirection など) を介してサブコンポーネント RichText を返すことがわかります。 外部データの変更。

では、StatelessWidget はどのようなシナリオで使用する必要があるのでしょうか?

ここで、単純な判断ルールがあります。親ウィジェットは、初期化パラメーターによって UI 表示効果を完全に制御できるか? その場合は、StatelessWidget を使用してコンストラクタ インターフェイスを設計できます。

この判断ルールを理解するのに役立つ 2 つの簡単な小さな例が用意されています。

最初の小さな例は、カスタム ポップアップ コントロールを作成して、アプリの使用中に発生するエラー メッセージをユーザーに表示する必要があることです。このコンポーネントの親 Widget は、コンポーネントが必要とするスタイル情報とエラー メッセージを、初期化時に子 Widget に完全に渡すことができます。つまり、親 Widget は、初期化パラメーターを通じて表示効果を完全に制御できます。したがって、StatelessWidget を継承することでコンポーネントをカスタマイズできます。

2 番目の小さな例は、カウンター ボタンを定義する必要があることです.ユーザーがボタンをクリックするたびに、ボタンの色が暗くなります. このコンポーネントの親 Widget は、子 Widget の初期スタイル表示効果のみを制御でき、対話中に発生する色の変化を制御できないことがわかります。したがって、StatelessWidget を継承してコンポーネントをカスタマイズすることはできません。さて、今度は StatefulWidget がプレイする番です。

ステートフルウィジェット

StatelessWidget に対応して、いくつかの Widgets (Image、Checkbox など) が表示されます. 親 Widget が初期化されるときに渡される静的な構成に加えて、ユーザーの操作 (たとえば、ユーザーがボタンをクリックする) または内部データの変更 (ネットワーク データ リターン パケットなど) を UI に反映します。

言い換えれば、これらのウィジェットが作成された後、それらは再描画するためにデータの変更に気を配り、対応する必要があります。Flutter では、このタイプのウィジェットを StatefulWidget (ステートフル コンポーネント) と呼びます。以下は、StatefulWidget の図です。

ウィジェットは不変であり、変更が発生したときに破棄して再構築する必要があるため、状態はありません。それで、ここで何が起こっているのですか?

実際、StatefulWidget は State クラスのエージェント Widget 構築の設計法によって実現されています。次に、Image のソース コードの一部を例として StatefulWidget の構築プロセスを説明し、この知識ポイントを理解できるようにします。

上記の Text と同様に、Image クラスのコンストラクターは、このクラスで使用されるプロパティ パラメーターを受け取ります。ただし、違いは、Image クラスにはビューを作成するビルド メソッドがなく、createState メソッドを使用して _ImageState タイプの状態オブジェクトを作成し、このオブジェクトがビューの構築を担当することです。

この状態オブジェクトは、Image クラスの状態変化を保持および処理するため、_imageInfo プロパティを例として使用して説明します。

_imageInfo 属性は、実際の画像をウィジェットにロードするために使用されます。State オブジェクトは、_handleImageChanged メソッドによって _imageInfo 属性が変更されたことを検出すると、すぐに _ImageState クラスの setState メソッドを呼び出して、Flutter フレームワークに通知します。が変更されました。更新された _imageInfo データで画像をリロードしてください!". 代わりに、Flutter フレームワークがビュー ステートをマークし、UI を更新します。


class Image extends StatefulWidget {
  //构造方法及属性声明部分
  const Image({
    Key key,
    @required this.image,
    //其他参数
  }) : assert(image != null),
       super(key: key);

  final ImageProvider image;
  //其他属性
  ...
  
  @override
  _ImageState createState() => _ImageState();
  ...
}

class _ImageState extends State<Image> {
  ImageInfo _imageInfo;
  //其他属性
  ...

  void _handleImageChanged(ImageInfo imageInfo, bool synchronousCall) {
    setState(() {
      _imageInfo = imageInfo;
    });
  }
  ...
  @override
  Widget build(BuildContext context) {
    final RawImage image = RawImage(
      image: _imageInfo?.image,
      //其他初始化配置
      ...
    );
    return image;
  }
 ...
}

ご覧のとおり、この例では、Image は動的な方法で動作します。つまり、変更をリッスンしてビューを更新します。親 Widget を介して UI 表示を完全に制御する StatelessWidget とは異なり、StatefulWidget の親 Widget はその初期化状態のみを定義し、独自のビューの実行状態はそれ自体で処理する必要があり、UI 表示はそれに応じてリアルタイムで更新されます。処理状況。

StatelessWidget と StatefulWidget のソース コードを通じて、これら 2 種類のウィジェットを理解します。このとき、StatefulWidget は状態変化に対応できるだけでなく、静的 UI も表示できるので、静的 UI しか表示できない StatelessWidget が存在する必要があるのでしょうか。

チェックボックス クラス

チェックボックス

チェックボックス自体は状態を維持しません。代わりに、チェックボックスの状態が変化すると、ウィジェットは onChanged コールバックを呼び出します。チェックボックスを使用するほとんどのウィジェットは、onChanged コールバックをリッスンし、新しい値でチェックボックスを再構築して、チェックボックスの外観を更新します。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  static const String _title = 'Flutter Code Sample';

  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(_title),
        ),
        body: const Center(
          child: MyStatefulWidget(),
        ),
      ),
    );
  }
}

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

  @override
  State<StatefulWidget> createState() {
    return _MyStatefulWidgetState();
  }
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  bool isChecked = false;

  @override
  Widget build(BuildContext context) {
    Color getColor(Set<MaterialState> states) {
      const Set<MaterialState> interactiveStates = <MaterialState>{
        MaterialState.pressed,
        MaterialState.hovered,
        MaterialState.focused
      };
      if (states.any(interactiveStates.contains)) {
        return Colors.blue;
      }
      return Colors.red;
    }

    return Checkbox(
      checkColor: Colors.white,
      fillColor:
          MaterialStateProperty.resolveWith((states) => getColor(states)),
      value: isChecked,
      onChanged: (bool? value) {
        setState(() {
          isChecked = value!;
        });
      },
    );
  }
}

 

 TextField クラス

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(_title),
        ),
        body: const Center(
          child: MyStatefulWidget(),
        ),
      ),
    );
  }
}

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

  @override
  State<StatefulWidget> createState() {
    return _MyStatefulWidgetState();
  }
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  late TextEditingController _controller;

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: TextField(
        controller: _controller,
        onSubmitted: (String value) async {
          await showDialog(
              context: context,
              builder: (BuildContext context) {
                return AlertDialog(
                  title: const Text("THanks"),
                  content: Text(
                      'You typed "$value", which has length ${value.characters.length}.'),
                  actions: <Widget>[
                    TextButton(
                        onPressed: () {
                          Navigator.pop(context);
                        },
                        child: const Text("OK"))
                  ],
                );
              });
        },
      ),
    );
  }
}

 

StatefulWidget は注意して使用する必要があります

UI フレームワークの場合、通常、さまざまなコントロールを使用して同じ表示効果を実現できます。定義の観点からは、StatefulWidget は全能であるように思われ、StatelessWidget を置き換えるのが合理的です。したがって、StatefulWidget の悪用は論理的になりやすく、避けられません。

しかし、実際には、StatefulWidget を悪用すると、Flutter アプリケーションのレンダリング パフォーマンスに直接影響します。

Widget の更新メカニズムを見ると、StatefulWidget を完全に使用するには代償があります。

ウィジェットは不変で、更新は破棄 + 再構築 (ビルド) を意味します。StatelessWidget は静的であり、作成後に更新する必要はありません。StatefulWidget の場合、State クラスで setState メソッドを呼び出してデータを更新すると、ビューの破棄と再構築がトリガーされ、ビューのそれぞれの破棄と再構築も間接的にトリガーされます。サブウィジェット。

ルート レイアウトが StatefulWidget の場合、State の UI を更新する呼び出しはすべて、ページ全体のすべてのウィジェットを破棄して再構築します。

Flutter は Element レイヤーを内部的に使用して、実際のレンダリング ビューの変更を最小限に抑え、レンダリング効率を向上させますが、RenderObject ツリー全体を破棄して再構築するのではありません。ただし、多数の Widget オブジェクトの破棄と再構築は避けられません。サブウィジェットの再構築に時間のかかる操作が含まれる場合、ページのレンダリング パフォーマンスが急激に低下します。

ビューの表示要件を適切に評価し、StatefulWidgets の不必要な使用を避けることは、Flutter アプリケーションのレンダリング パフォーマンスを改善するための最も簡単で直接的な方法です。

ウィジェットは親から子へ、上から下へ構築されるため、コンポーネントをカスタマイズする場合、親ウィジェットが初期化パラメーターを通じて UI 表示効果を完全に制御できるかどうかという基本原則に従って、StatelessWidget を継承するかどうかを判断できます。

Flutter は要素レイヤーを介して実際のレンダリング ビューの変更を最小限に抑えますが、多数のウィジェットの破棄と再構築は避けられないため、StatefulWidget の悪用を回避することが、アプリケーションのレンダリング パフォーマンスを向上させる最も簡単で直接的な方法です。State を介して UI を積極的に更新することに加えて、いくつかの特別なシナリオでは、Widget の build メソッドが複数回実行される場合があることに注意してください。したがって、このメソッド内に時間のかかる操作をあまり配置しないでください。

おすすめ

転載: blog.csdn.net/zhangying1994/article/details/129111160