Flutter移動應用:狀態管理

原文連接https://siques.cn/p/41
這個章節咱們會先介紹一下 Flutter 的 StatelessWidget ,還有 StatefulWidget app

而後會用一個很是簡單的例子來理解一下 Flutter 應用的狀態管理 .. 狀態就是小部件裏的數據 .. 小部件能夠本身管理須要的數據 .. 這些數據也能夠經過小部件的構造函數從它的父輩那裏傳遞過來 ..less

咱們還會學一下,使用 InheritedWidget ... 還有 ScopedModel,更有效的去把數據傳遞給須要的小部件 ...ide

小部件

StatelessWidget:無變化狀態的小部件

StatelessWidget,這種小部件裏面不包含能夠變化的狀態,State 指的就是狀態,狀態能夠想成是小部件裏的數據 .. 也就是 StatelessWidget 小部件一但被建立之後 .. 它裏面的狀態通常不會有什麼變化 ..
img
下面再把 count 的值輸出到控制檯上檢查一下 .. 打開調試控制檯 ..函數

按一下界面上的這個漂浮按鈕 .. 你會發現,每次按這個按鈕的時候,count 的值都會加上 1 ... 不過在界面上這個 Chip 裏面顯示的 count 的值沒有發生改變 ..ui

咱們建立的小部件的狀態會根據用戶行爲發生變化 ... 這個時候咱們須要考慮使用另外一種小部件,StatefulWidget ..this

StatefulWidget:帶變化狀態的小部件

StatefulWidget,這種類型的小部件裏面能夠有一些可以變化的狀態 .. 也就是 StaefulWidget 構建的用戶界面能夠動態的發生變化 .. 好比在咱們這個例子裏面 .. 點了這個漂浮按鈕,界面上顯示的這個數字要動態的發生變化 .. 這種狀況咱們就可使用一個 StaefulWidget ..spa

下面能夠把咱們這個小部件改形成一個 StatefulWidget .. 讓它繼承一下 StatefulWidget .. 要注意的是 StaefulWidget 小部件自己也是 immutable ,不可改變的 ..調試

小部件須要的能夠變化的那些狀態要單獨放在一個 State 對象裏面 .. 這個 State 對象可使用小部件裏的 createState 這個方法來建立 .
imgcode

而後到模擬器上再試一下 .. 按一下這個動做按鈕 .. count 的值會加上 1,這個變化是在 setState 方法裏面完成的,因此每次有變化,小部件都會使用新的狀態被重建 .. 重建之後,界面上會顯示小部件變化以後的狀態 ..對象

狀態管理(由父輩管理狀態)

在咱們這個 StateManagementDemo 小部件裏面 .. 小部件的狀態是它本身管理的 .. 它須要的全部的狀態都在這個小部件本身這裏 .. 有時候這個狀態可能在小部件的父輩那裏 .. 把 State 從父輩那裏傳遞過來,能夠經過小部件的構造函數 ..

img
使用這個 Counter 的時候,如今須要提供一個 count 屬性 .. 這個屬性的值可使用上面定義的這個 _count ...

如今 Counter 小部件裏面須要的數據是從它爸爸,也就是 StateManagementDemo 那裏傳遞過來的 ...

從父輩那裏傳遞個回調

下面咱們再改造一下這個 Counter 小部件 .. 把這個 Chip 換成一個 ActionChip ,這樣能夠給它一個 onPressed 屬性,設置一下點按這個 Chip 要執行的動做 .. 我想在按它的時候也可讓 _count 的值加上 1 ..

若是在這個 Counter 小部件裏面設置它的這個 count ,界面上顯示的數字是不會有什麼變化的 .. 由於這個數字實際上是 StateManagementDemo 裏面的 _count 的的值 ..
img

按一下界面上的這個 ActionChip ... 執行的就是它爸爸傳遞過來的一個回調 .. 作的事兒就是讓小部件的 _count 的值加上 1 ..

再按一下漂浮動做按鈕 .... 一樣能夠增長 _count 的值 ...

狀態樹

img
如今,在 Counter 裏面須要的數據是經過小部件的構造函數,從 StateManagementDemo 那裏直接傳遞過來的 .. 假設在這兩個小部件之間還有一個小部件 .. 好比可能有一個 CounterWrapper .. 在這個 CounterWrapper 裏面使用了 Counter ...

這樣,這個 Counter 須要的數據要先從 StateManagementDemo 傳遞給 CounterWrapper .. 而後再由這個 CounterWrapper 傳遞給 Counter .. 須要一級一級往下傳 ..
img

InheritedWidget

InheritedWidget:直接把數據傳遞給須要的小部件

在咱們這個示例裏面,Counter 小部件須要的數據是從 StateManagementDemo 傳遞給 CounterWrapper,又從 CounterWrapper 傳遞給了 Counter ... 如今咱們須要一種方法,能夠把數據直接傳遞給須要的小部件 .. 也就是 Counter 須要的數據能夠不經過 CounterWrapper,而是直接從 StateManagementDemo 那裏傳遞過來 ..

能夠試一下 Flutter 的 InheritedWidget .. 用法就是能夠去建立一個 InheritedWidget,在這個小部件裏面設置其它小部件須要的數據,而後把這個 InheritedWidget 放在小部件樹的某個地方,這樣在樹下面的小部件均可以直接訪問到在 InheritedWidget 小部件裏的數據了 ..
img

ScopedModel

ScopedModel:安裝與基本用法介紹

ScopedModel 也能夠把數據直接交給須要的小部件 .. 它是一個第三方的包,因此要使用它得先去安裝一下 .. 打開項目下面的 pubspec.yaml ..
img
使用 ScopedModel .. 咱們得先去建立一個 Model .. 在裏面添加須要的數據 .. 而後把 ScopedModel 小部件放到 Widget Tree 的某個位置上 .. 設置一下它的 model .. 這樣在它下面的小部件均可以直接訪問到它設置的 model 裏的東西 ..

使用 ScopedModel 傳遞數據

先建立一個 Model .. 添加一個類 .. 名字能夠是 CounterModel .. 它要繼承一下 Model ... 再導入須要的包 .. 就是以前咱們安裝的這個 scoped_model ..

裏添加一個 int _count .. 讓它先等於 0 .. 再添加一個 getter 方法, 名字叫 count .. 讓它返回 _count 的值 ... 在使用了這個 model 的小部件裏面,可使用這個 getter 方法獲取到 _count 的值 ..

img
按一下界面上的 ActionChip ,會讓 CounterModel 的 _count 的值增長 1 ,有變化就會重建這個部件顯示出變化以後的樣子 ..

一樣,按一下漂浮動做按鈕,也可讓 CounterModel 裏的 _count 的值加上 1 ...
最終代碼

import 'package:flutter/material.dart';
import "package:scoped_model/scoped_model.dart";

class StateManagementDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScopedModel(
        model: CounterModel(),
        child: Scaffold(
            appBar: AppBar(
              title: Text('StateManagementDemo'),
              elevation: 0.0,
            ),
            body: CouterWrapper(),
            floatingActionButton: ScopedModelDescendant<CounterModel>(
              rebuildOnChange: false,
              builder: (context, _, model) => FloatingActionButton(
                child: Icon(Icons.add),
                onPressed: model.increaseCount,
              ),
            )));
  }
}

class CouterWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Counter(),
    );
  }
}

class Counter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScopedModelDescendant<CounterModel>(
        builder: (context, _, model) => ActionChip(
              label: Text('${model.count}'),
              onPressed: model.increaseCount,
            ));
  }
}

class CounterProvider extends InheritedWidget {
  final int count;
  final VoidCallback increaseCount;
  final Widget child;

  // 構造函數
  CounterProvider({this.count, this.increaseCount, this.child})
      : super(child: child);

  static CounterProvider of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType();

  @override
  bool updateShouldNotify(InheritedWidget oldWidget) {
    return true;
  }
}

class CounterModel extends Model {
  int _count = 0;
  int get count => _count;

  void increaseCount() {
    _count += 1;
    notifyListeners();
  }
}
相關文章
相關標籤/搜索