Flutter

Flutter状态管理(四)scoped_model

2020-09-08  本文已影响0人  天色将变
简介

scoped_model是一个简单的第三方状态管理框架,它的源码只有一个dart文件,代码量非常少,巧妙的利用了InheritedWidget和AnimatedBuilder的特性,达到了状态管理的目的。
官网地址:https://pub.flutter-io.cn/packages/scoped_model

如何安装
dependencies:
  scoped_model: ^1.0.1
代码示例

还是那个点击按钮+1的示例,改用scoped_model实现:


image.png
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
class ScopedModelTest extends StatefulWidget {
  @override
  _ScopedModelTestState createState() => _ScopedModelTestState();
}

class _ScopedModelTestState extends State<ScopedModelTest> {
  // 创建model
  CountModel _model = CountModel();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("ScopedModel"),
        centerTitle: true,
      ),
      body: Center(
        child: ScopedModel<CountModel>(
          model: _model,
          child: CountWidget(),// 要将使用model中数据的widget成为ScopedModel的子widget
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: (){
          _model.increment();// 出发model的+1方法
        },
      ),
    );
  }
}

// 自定义Model
class CountModel extends Model{
  // 要共享的状态数据
  int _counter = 0;
  int get counter => _counter;
  // +1的方法
  void increment(){
    ++_counter;
    notifyListeners();
  }
}

// 使用了状态数据的Widget
class CountWidget extends StatefulWidget {
  @override
  _CountWidgetState createState() => _CountWidgetState();
}

class _CountWidgetState extends State<CountWidget> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: ScopedModelDescendant<CountModel>(
        builder: (context,child,model){
          return Text(model.counter.toString());
        },
      ),
    );
  }
}

解析:

ScopedModel<CountModel>(
          model: _model,
          child: CountWidget(),// 要将使用model中数据的widget成为ScopedModel的子widget
        ),

接收两个参数:model是前面创建的CountModel,也就是_counter所在的数据,是需要通过floatingActionButton去进行操作的。child是依赖CountModel的Widget。ScopedModel内部最终是将model和child传递给了一个InheritedWidget,利用InheritedWidget的特性将model从渲染树中下传到了CountWidget。

核心原理
源码分析

注意这里列出的源码都是删减版的,只保留了核心内容

abstract class Model extends Listenable {
  // 维护了一个回调的set
  final Set<VoidCallback> _listeners = Set<VoidCallback>();
  /// 在AnimatedWidget的initState内调用该方法
  @override
  void addListener(VoidCallback listener) {
    _listeners.add(listener);
  }

  /// CountModel中increment方法内部调用该方法,将所有的回调给执行。
  @protected
  void notifyListeners() {
    _listeners.toList().forEach((VoidCallback listener) => listener());
  }
}
class ScopedModel<T extends Model> extends StatelessWidget {
  /// The [Model] to provide to [child] and its descendants.
  final T model;

  /// The [Widget] the [model] will be available to.
  final Widget child;

  ScopedModel({@required this.model, @required this.child})
      : assert(model != null),
        assert(child != null);

  @override
  Widget build(BuildContext context) {
    // 注意深追AnimatedBuilder,--> AnimatedWidget  
    return AnimatedBuilder(
      animation: model,
      builder: (context, _) => _InheritedModel<T>(model: model, child: child),
    );
  }
}
abstract class AnimatedWidget extends StatefulWidget {
  const AnimatedWidget({
    Key key,
    @required this.listenable,
  }) : assert(listenable != null),
       super(key: key);

  final Listenable listenable;

  @override
  _AnimatedState createState() => _AnimatedState();

}

class _AnimatedState extends State<AnimatedWidget> {
  @override
  void initState() {
    super.initState();
    widget.listenable.addListener(_handleChange);
  }
  void _handleChange() {
    setState(() {
      // The listenable's state is our build state, and it changed already.
    });
  }

}

class _InheritedModel<T extends Model> extends InheritedWidget {
  final T model;
  final int version;

  _InheritedModel({Key key, Widget child, T model})
      : this.model = model,
        this.version = model._version,
        super(key: key, child: child);

  @override
  bool updateShouldNotify(_InheritedModel<T> oldWidget) =>
      (oldWidget.version != version);
}
class ScopedModelDescendant<T extends Model> extends StatelessWidget {
 
  @override
  Widget build(BuildContext context) {
    return builder(
      context,
      child,
      ScopedModel.of<T>(context, rebuildOnChange: rebuildOnChange),
    );
  }
}

typedef Widget ScopedModelDescendantBuilder<T extends Model>(
  BuildContext context,
  Widget child,
  T model,
);
上一篇 下一篇

猜你喜欢

热点阅读