Flutter 组件刷新

作者: 来自蒙塔基的钢蛋儿 | 来源:发表于2020-07-16 22:15 被阅读0次

介绍一下数据与Widget之间传递,数据改变-->触发Widget刷新

1.0 所需工具

  • Provider

2.0 Provider

Provider 会在WidgetModel之间建立监听,以确保数据发生变化时刷新Widget

3.0 必要步骤:

  • Model 要继承ChangeNotifier
  • Widget要监听Model数据变化

Provider 是flutter推荐使用的状态管理工具,具体原理这里不展开分析,下面介绍一下如何快速使用,达到一个真实业务的场景.

4.0 Model创建

// 重要: model必须继承ChangeNotifier
class TestClass with ChangeNotifier {
  var count = 1;

  action() {
    ++count;
    //数据变化后腰通过 notifyListeners() 通知所有监听者
    notifyListeners();
  }
}

4.1 监听Model

Model监听有两种方式

  1. 通过addListener方式
  2. 通过Provider.of<T>(context)

4.1.1 通过 addListener 监听数据改变

当数据改变并且调用 notifyListeners() 这里会收到回调

model.addListener(() { 
      //Do something
});

4.1.2 通过 Provider.of<T>(context) 方式监听

这里看到在build方法中我们获取Provider传入的Model.并没有调用addListener.这里解释一下.
通过查看 Provider.of 源码中知道, Provider.of通过 context 将本次构建的build方法绑定,并监听数据改变. 所以在数据变化后将自动调用 build 方法进行刷新.

  @override
  Widget build(BuildContext context) {
    final model = Provider.of<TestClass>(context);
    return Container()
  }

5.1 向下传递完整示例

下面将一个Model向下传递的完整实例贴出来.

import 'package:provider/provider.dart';

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

class TestClass with ChangeNotifier {
  var count = 1;
  action() {
    ++count;
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<TestClass>(
      create: (context)=>TestClass(),
      child: MaterialApp(
        theme: ThemeData.dark(),
        home: FirstScreen(),
      ),
    );
  }
}

class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final model = Provider.of<TestClass>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('Provider'),
      ),
      body: Container(
        child: Center(child: Text("${model.count}",style: TextStyle(fontSize: 50),),),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => model.action(),
        child: Icon(Icons.add),
      ),
    );
  }
}

5.2 组件内部通过Model控制数据刷新 完整示例

import 'package:provider/provider.dart';

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

class TestClass with ChangeNotifier {
  var count = 1;
  action() {
    ++count;

    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      home: FirstScreen(),
    );
  }
}

class FirstScreen extends StatelessWidget {
  final TestClass source=TestClass();
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('Provider'),
      ),
      body:ChangeNotifierProvider<TestClass>(
        create: (context) => source,
        child: Consumer<TestClass>(
          child: Container(),
          builder: (context, model, child) {
            return Container(
              child: Center(child: Text("${model.count}",style: TextStyle(fontSize: 50),),),
            );
          },
        ),
      ),
      
      floatingActionButton: FloatingActionButton(
        onPressed: () => source.action(),
        child: Icon(Icons.add),
      ),
    );
  }
}

6.0 Provider封装

5.2 数据内部控制刷新示例看出,实际代码写起来比较麻烦.所以封装了一下. 只需要传入必要参数就可以.

6.1 封装Widget

class RefreshWidget<T extends ChangeNotifier> extends StatelessWidget {
  RefreshWidget(
      this.builder, {
        @required this.source,
        this.child,
      });

  final T source;
  final Function(BuildContext context, T value, Widget child) builder;
  final Widget child;

  static Builder<T>(
      Function(BuildContext context, T value, Widget child) builder) {
    return builder;
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<T>(
      create: (context) => source,
      child: Consumer<T>(
        child: child,
        builder: (context, model, child) {
          return builder(context, model, child);
        },
      ),
    );
  }
}

6.2 封装后使用对比

封装前

ChangeNotifierProvider<TestClass>(
        create: (context) => source,
        child: Consumer<TestClass>(
          child: Container(),
          builder: (context, model, child) {
            return Container(
              child: Center(child: Text("${model.count}",style: TextStyle(fontSize: 50),),),
            );
          },
        ),
      ),

封装后

RefreshWidget<TestClass>(
          (context, value, child) => Container(
                child: Center(
                  child: Text(
                    "${value.count}",
                    style: TextStyle(fontSize: 50),
                  ),
                ),
              ),
          source: source),
封装后我们只需要关心下面三点,对与新手比较友好,不用纠结太多
  • builder构建方法
  • source数据model
  • <T> model 类型

相关文章

网友评论

    本文标题:Flutter 组件刷新

    本文链接:https://www.haomeiwen.com/subject/wsimhktx.html