美文网首页Flutter系列教程
使用InheritedWidget实现管理父Widget传值到子

使用InheritedWidget实现管理父Widget传值到子

作者: 嗨哒哥 | 来源:发表于2020-02-24 14:56 被阅读0次

    使用InheritedWidget实现管理父Widget传值到子Widget

    在开发过程中,父Widget拿到网络请求值,或者当前状态改变需要更改子Widget的时候,就涉及到把父Widget获取到的值传递给子Widget。这个时候可以通过子Widget定义的时候定义好要接收的方式;方法固然可行,但是有没有别的更好传值方式?这里我们介绍下使用InheritedWidget来实现在当前页面数据共享。

    先来看下通过定义的方式传值

    现在定义一个是StatefulWidget类型的ListViewHttpDemo。在ListViewHttpDemoState的build中返回一个自定义的CustomGridView,CustomGridView在创建的时候接收一个可选的List<DataModel>数组,这个数据就就相当于创建CustomGridView接收的来自于父Widget的数据传递。

    来看下CustomGridView的定义:

    class CustomGridView extends StatelessWidget {
      final List<DataModel> listData;//接收数据,用于创建GridView
      CustomGridView({Key key, this.listData}):super(key:key);
    
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Center(
          child: GridView(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 1,
                childAspectRatio: 2.1,
                mainAxisSpacing: 16.0,
                crossAxisSpacing: 10.0
            ),
            children: _getGridView(),
          ),
        );
      }
      List<Widget> _getGridView() {
        return listData.map<Widget>((dataModel) => Container(
          alignment: Alignment.center,
          padding: EdgeInsets.only(left:10.0, right: 10.0),
          child: Stack(
            children: <Widget>[
              Image.network(dataModel.imageUrl,fit: BoxFit.cover,),
              Positioned(
                  left: 16.0,
                  top: 16.0,
                  child: Container(
                    child: Text(dataModel.title, style: TextStyle(
                        color: Colors.red,
                        fontSize: 20.0,
                        fontWeight: FontWeight.bold
                    ),),
                  )),
              Positioned(
                  left: 16.0,
                  right: 16.0,
                  top: 40.0,
    //             height: 60,
                  child: Text(dataModel.subTitle, style: TextStyle(
                    color: Colors.white,
                    fontSize: 14.0,
                  ),))
            ],
          ),
        )).toList();
      }
    
    }
    

    在CustomGridView的父Widget:ListViewHttpDemoState中通过调用‘CustomGridView(listData: _listData,)’,来传递CustomGridView构建自身Widget所需要的数据:

    class ListViewHttpDemoState extends State<ListViewHttpDemo> {
      List<DataModel> _listData = new List();//生命一个数组
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        getData();//获取数据
      }
      void getData() async {
        _listData = await HttpUtils.getListData();//网络请求对象
        if(_listData.length > 0) {
          if(mounted) {//判断当前WIdget是否还存在,存在的话更新数据
            setState(() {});
          }
        }
      }
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return CustomGridView(listData: _listData,);//创建子Widget并传递数据
      }
    }
    

    这种数据传递的方式最为普通,也最为常见。

    接下来通过InheritedWidget在当前Widget共享数据

    InheritedWidget在flutter中是一个比较特殊的存在,使用它可以实在在当前Widget页面中实现数据共享,并且在当前Widget中的子Widget通过xxx.of(context)来获取存储在InheritedWidget中的数据。

    先来定义一个数据模型DataModel:

    class DataModel{
      final String title;
      final String subTitle;
      final String imageUrl;
      DataModel(
          this.title,
          this.subTitle,
          this.imageUrl);
    
      DataModel.changeToModel(Map jsonMap)
          :title=jsonMap['title'],
            subTitle=jsonMap['subTitle'],
            imageUrl=jsonMap['imageUrl'];
    
    }
    

    这个模型用于保存从网络中获取的数据,数据获取后,就存放在我们自定义的InheritedWidgetModel中,InheritedWidgetModel的定义如下:

    class InheritedWidgetModel extends InheritedWidget {
      List<DataModel> listDate;//保存的数据
      final Widget child;//子widget
    
      //构造函数,初始化的时候调用
      InheritedWidgetModel({Key key, this.listDate, this.child}):super(key:key,child:child);
    
      //用于获取自定义的InheritedWidgetModel,然后在获取InheritedWidgetModel里面的数据
      static InheritedWidgetModel of (BuildContext context) {
        final InheritedWidgetModel model = context.inheritFromWidgetOfExactType(InheritedWidgetModel);
        return model;
      }
    
      @override
      bool updateShouldNotify(InheritedWidgetModel oldWidget)  {
        bool flag = listDate != oldWidget.listDate;
        return flag;
      }
    
    }
    

    定义好模型和InheritedWidget之后,就要去使用它。

    1、在创建当前页面Widget的时候声明InheritedWidgetModel
    class InheritDemo extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return InheritedWidgetModel(//下面的子Widget要使用共享数据,就必须在父Widget中声明
          listDate: new List(),//初始化数据
          child: MaterialApp(
            home: Scaffold(
              appBar: AppBar(
                title: Text('InheritedWidget'),
                actions: <Widget>[
                  Icon(Icons.add_box)
                ],
              ),
              body: ListViewHttpDemo(),
    //      floatingActionButton: ,
            ),
          ),
        );
      }
    }
    
    2、在ListViewHttpDemo状态中调用ListViewHttpInheritDemoState
    class ListViewHttpDemo extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        // TODO: implement createState
        return ListViewHttpInheritDemoState();
      }
    }
    
    3、在ListViewHttpInheritDemoState中初始化数据

    在这个Widget中的initState方法里面进行网络数据请求:

    @override
      void initState() {
        // TODO: implement initState
        super.initState();
        getData();//请求数据
      }
      void getData() async {
        List<DataModel> listDate = await HttpUtils.getListData();
        if(listDate.length > 0) {
        //如果数据不为空,更新InheritedWidgetModel里面的数据
          InheritedWidgetModel.of(context).listDate = listDate;
          if(mounted) {//判断当前Widget是否还存在
            setState(() {});//刷新Widget
          }
        }
      }
    
    4、在自定义CustomInheritGridView中使用数据

    数据准备完毕之后,就需要使用:

    class CustomInheritGridView extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Center(
          child: GridView(创建GridView
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 1,
                childAspectRatio: 2.1,
                mainAxisSpacing: 16.0,
                crossAxisSpacing: 10.0
            ),
            children: CustomGridViewDemo.getGridView(//创建children数组
                InheritedWidgetModel.of(context) == null ? null : InheritedWidgetModel.of(context).listDate),
          ),
        );
      }
    }
    

    接下来运行看下效果,在没有数据的时候,会在中间显示一个‘数据正在加载中。。。。’,等数据加载完成之后就会出现有数据的页面


    demo.gif

    整个InheritedWidget的使用过程到此结束。
    总结一下就是说:

    1、要先创建一个继承自InheritedWidget的InheritedWidgetModel
    2、在需要使用的父WIdget中使用InheritedWidgetModel来创建
    3、数据获取后向InheritedWidgetModel更新数据
    4、子Widget使用数据。
    

    本节中使用的代码

    InheritDemo

    HttpUtils

    InheritedWidgetModel

    DataModel

    CustomGridViewDemo

    相关文章

      网友评论

        本文标题:使用InheritedWidget实现管理父Widget传值到子

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