Flutter StatefullWidget 三種狀態管理Demo

在Flutter中,組件的狀態管理還是非常重要的,組件要麼是無狀態的組件,要麼是有狀態的組件。無狀態的組件使用起來似乎並不複雜,有狀態的組件又是怎麼管理的呢?這裏就談一談 StatefullWidget 與 State 對組件狀態的管理。狀態管理又可以分爲三類:自己管理,父組件管理,父子組件混合管理。

第一種自己的狀態自己管理,是最簡單的一種,看代碼;

import 'package:flutter/material.dart';
//自己的狀態自己管理,繼承StatefulWidget
class SelfManageStatus extends StatefulWidget{

  @override
  State<StatefulWidget> createState() {
    return _SelfManageStatusState();
  }
}
//狀態類,一個StatefulWidget 對應一個 State
class _SelfManageStatusState extends State<SelfManageStatus>{
  //點擊次數,默認 0
  int clickNum = 0;
  //點擊事件
  void doClick(){
    // 狀態由調用setState()管理
    setState(() {
      // 每次點擊加 1
      clickNum++;
    });
  }

  /// 構建控件元素
  @override
  Widget build(BuildContext context) {
    // 使用GestureDetector監測手勢相關事件
    return GestureDetector(
      onTap: doClick,
      child: Container(
          child: Center(
              child: Column(
                children: <Widget>[
                    Text(
                      "自己管理,點我呀",
                      style: TextStyle(fontSize: 18,color: Colors.yellow),
                    ),
                    Text("點擊次數:$clickNum"),
                  ],
              )
        ),
        //寬度,double.infinity:百分之百
        width: double.infinity,
        height: 100,
        color: Colors.red
      ),
    );
  }
}

說明:通過這個demo可以看出,StatefulWidget 與 State 的使用是一一對應的,狀態管理交由 State 處理;手勢在手機屏幕上滑動通過 GestureDetector類檢測,狀態的管理通過 State 類的 setState() 方法控制。把 setState() 這個方法去掉,就做不到狀態的保持。

第二種情況,父組件管理;

//父管理子狀態,父組件繼承StatefulWidget
class ParentManageStatus extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    return _ParentManageStatusState();
  }
}
//父組件狀態
class _ParentManageStatusState extends State<ParentManageStatus>{
  //點擊次數,默認0
  int clickNum = 0;
  //當數量發生改變時,由父組件調用setState()管理狀態
  void handleClick(int num){
    setState(() {
      //每點擊一次加num,該num由子組件傳遞過來
      clickNum+=num;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Container(
      child: ChildArea(
        clickNum : clickNum,
        numChanged : handleClick,
      ),
    );
  }
}
//子組件繼承StatelessWidget無狀態組件
class ChildArea extends StatelessWidget{
  //不可改變的點擊數量
  final clickNum;
  //狀態的傳遞
  final ValueChanged<int> numChanged;  
  ChildArea({this.clickNum, required this.numChanged});
  //點擊事件
  void doClick(){
    /// 沒有去管理狀態,交由父類管理
    numChanged(1);
  }
  @override
  Widget build(BuildContext context) {
    // 使用GestureDetector監測手勢相關事件
    return GestureDetector(
      // 點擊事件監聽
      onTap: doClick,
      child: Container(
        child: Center(
            child: Column(
              children: <Widget>[
                Text(
                  "子組件父管理,點我呀",
                  style: TextStyle(fontSize: 18,color: Colors.yellow),
                ),
                Text("點擊次數:$clickNum"),
              ],
            )
        ),
        width: double.infinity,
        height: 100,
        color: Colors.green
      ),
    );
  }
}

說明:子組件繼承 StatelessWidget 無狀態組件,對組件的狀態無需管理,監聽到點擊事件時,將狀態交由父組件管理,父組件管理後再傳遞過來回顯。父組件管理就是一個有狀態的組件和無狀態的組件的結合。

第三種情況,狀態混合管理;

import 'package:flutter/material.dart';

//父子狀態混合管理,父組件
class HybridManageStatus extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    return _HybridManageStatusState();
  }

}
//父組件狀態
class _HybridManageStatusState extends State<HybridManageStatus>{
  // 子點擊次數
  int clickNum = 0;
  // 父點擊次數
  int pclickNum = 0;
  //點擊事件,調用setState()進行狀態保持
  void handleClick(int num){
    setState(() {
      clickNum = num;
      pclickNum++;
    });
  }
  //點擊事件,調用setState()進行狀態保持
  void doClick(){
    setState(() {
      pclickNum++;
    });
  }
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        onTap: doClick,
        child: Container(
              child: Center(
                child: Column(
                children: <Widget>[
                ChildStatus(
                clickNum: this.clickNum,
                  numChanged: handleClick,
                ),
                Text(
                  "混合管理,我是父組件裏的控件",
                  style: TextStyle(fontSize: 18,color: Colors.yellow),
                ),
                Text("子點擊次數:$clickNum,父點擊次數:$pclickNum"),
                ],
              ),
            ),
            width: double.infinity,
            height: 200,
            color: Colors.grey
         ),
    );
  }

}
//子組件
class ChildStatus extends StatefulWidget{

  final clickNum;

  final ValueChanged<int> numChanged;

  ChildStatus({this.clickNum, required this.numChanged});

  @override
  State<StatefulWidget> createState() {
    return _ChildStatusState();
  }
}
//子組件狀態
class _ChildStatusState extends State<ChildStatus>{
  int clickNum = 0;
  void doClick(){
    setState((){
      clickNum++;
    });
    widget.numChanged(clickNum);
  }
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: doClick,
      child: Container(
        child: Center(
            child: Column(
              children: <Widget>[
                Text(
                  "混合管理,我是父組件裏的子組件控件,點我呀",
                  style: TextStyle(fontSize: 18,color: Colors.yellow),
                ),
                Text("點擊次數:$clickNum"),
              ],
            )
        ),
        width: double.infinity,
        height: 100,
        color: Colors.blue,
      ),
    );
  }
}

說明:

  1. 混合管理,父組件是有狀態的組件,子組件也是有狀態的組件,是兩個有狀態組件的結合,子組件狀態的變更會通知父組件(最重要的一點)。混合管理對於新手來說,還是有點複雜的,但也是使用頻率最多的狀態管理,所以必須熟練掌握。
    2.這個demo裏,在父組件裏又單獨加了一個組件,作爲參照,父組件包含子組件,但是父組件的控件在子組件範圍外,子組件以外的父組件只受父組件的影響,和子組件無關。

代碼寫完了,將這三種狀態整合起來

import 'package:flutter/material.dart';

import 'OneArea.dart';
import 'ThreeAreaParent.dart';
import 'TwoAreaParent.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text("welocom to flutter"),
        ),
        body: Center(
          child: ThreeState(),
        ),
      ),
    );
  }
}
//繼承無狀態組件,整合三種狀態的組件
class ThreeState extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Container(
        child: Column(
          children: <Widget>[
            OneArea(),
            TwoAreaParent(),
            ThreeAreaParent()
          ],
        )
    );
  }
}

運行代碼,每一塊各點擊三下,確認統計數字是否正確;


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章