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();
  }
}
相关文章
相关标签/搜索