美文网首页Flutter圈子FlutterFlutter中文社区
flutter之provider使用与简单封装

flutter之provider使用与简单封装

作者: waiwaaa | 来源:发表于2020-05-14 22:32 被阅读0次

    Provider是目前Google推荐的状态管理库,国内镜像的地址,现在的最新版本是4.1.1,但是我的sdk版本是1.16,不支持这个最新的,所以改版本用的4.0.0

    基本使用

    我先是以最简单的主题更改来做基本的更改

    第一步,添加Provider依赖,pubspec.yaml

    dependencies:
      provider: ^4.0.0
    

    第二步,创建Model

    import 'package:flutter/material.dart';
    
    class ThemeModel with ChangeNotifier {
      ThemeData themeData = light();
    
      bool lighted = true;
    
      changeTheme() {
        if (lighted) {
          themeData = dark();
        } else {
          themeData = light();
        }
        lighted = !lighted;
    
        notifyListeners();
      }
    
      static ThemeData light() {
        return ThemeData(
          textTheme: TextTheme(
              subtitle1: TextStyle(
            color: Colors.black,
            fontSize: 16,
          )),
          backgroundColor: Colors.white,
          brightness: Brightness.light,
          primaryColor: Color(0xff248bfe),
          appBarTheme: AppBarTheme(
            elevation: 0,
            textTheme: TextTheme(
                subtitle1: TextStyle(
              color: Colors.white,
              fontSize: 16,
            )),
          ),
        );
      }
    
      ThemeData dark() {
        return ThemeData(
          textTheme: TextTheme(
              subtitle1: TextStyle(
            color: Colors.white,
            fontSize: 16,
          )),
          backgroundColor: Colors.black,
          brightness: Brightness.dark,
          primaryColor: Color(0xff000000),
          appBarTheme: AppBarTheme(
            elevation: 0,
            textTheme: TextTheme(
                subtitle1: TextStyle(
              color: Colors.white,
              fontSize: 16,
            )),
          ),
        );
      }
    }
    
    

    一个白天模式一个夜间模式,数据需要混入ChangeNotifier,数据更改后需要调用notifyListeners();来发出通知。

    第三步,使用ChangeNotifierProvider

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context1) {
        return ChangeNotifierProvider<ThemeModel>(
          create: (_)=>new ThemeModel(),
          child: //这里必须用Builder,因为Provider.of<ThemeViewModel>(context,listen: true)要拿这里传入的context
            Builder(
              builder: (context)=>      
                MaterialApp(
                  debugShowCheckedModeBanner: false,
                  title: 'Flutter Demo',
                  theme:  Provider.of<ThemeModel>(context,listen: true).themeData,//通过Provider.of取值
                  routes: <String,WidgetBuilder>{
                    "main/mainpage":(BuildContext context1)=>new MainPage(), //为什么这里可以拿到context1,provider就不行呢???因为该context中并没有Provider
                  },
                  home: SplashPage(),
                )
            ),
        );
    
      }
    }
    
    
    • ChangeNotifierProvider提供数据,如果用Provider以后取的的model就感受不到变化了
    • child需要传入Builder,因为外层build方法的context把当前model没有包含进去,所以需要用build来取含有此modelcontext.
    • 通过Provider.of取到对应的model

    第四步,通过点击按钮,获取model并更改模式

    InkWell(
              onTap: (){
                Provider.of<ThemeModel>(context,listen:false).changeTheme();
              },
              child: Icon(Icons.cake),
            )
    

    简单的封装

    用provider对数据更改来刷新界面时,我们需要有效的控制数据的范围,如果全部放在最上层肯定会影响性能及数据的安全性。所以我们需要对provider写一个通用的组件,方便我们使用。

    ProviderWidget封装

    import 'package:flutter/cupertino.dart';
    import 'package:provider/provider.dart';
    
    class ProviderWidget<T extends ChangeNotifier> extends StatefulWidget{
      final T model;
      final Widget Function(BuildContext context, T value, Widget child) builder;
      final Function(T) onReady;
    
      ProviderWidget({this.model,this.onReady,this.builder});
    
      @override
      _ProviderWidgetState<T> createState() => _ProviderWidgetState<T>();    
    }
        
    class _ProviderWidgetState<T extends ChangeNotifier> extends State<ProviderWidget<T>> {
      @override
      void initState() {
        super.initState();
        if(widget.onReady!=null){
          widget.onReady(widget.model);
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider<T>(
          create: (_) => widget.model,
          child: Consumer<T>(//因为child
            builder: widget.builder,
          ),
        );
      }
    }
    
    • 泛型T是我们model的类型
    • builder是生成childbuilder, 不直接传入child还是因为之前说过的原因,构造对象的context需要是含有当前modelcontext才能取到此model,不然后报错。
    • 为了能取到context,我们此处用到了Consumer,合理的用Consumer可以减少刷新范围,这个类的具体说明请参考使用Provider前你应了解Consumer

    使用示例

    model类

    class TestModel with ChangeNotifier {
      int clickNum=0;
    
      void add() {
        clickNum++;
        notifyListeners();
      }
    }
    

    用widget的地方直接使用

    ProviderWidget<TestModel>(
            model:TestModel(), 
            onReady:(model){
              model.toString();
            }, 
            builder:(context, model, child){
              return Column(
                children: <Widget>[
                  Text("${model.clickNum}"),
                  RaisedButton(child:Text("add"),onPressed: (){
                      model.add();
                  })
                ],
              );
            },
          )
    

    本文完整源码请移步github

    相关文章

      网友评论

        本文标题:flutter之provider使用与简单封装

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