美文网首页
InheritedWidget 共享数据组件

InheritedWidget 共享数据组件

作者: ES_KYW | 来源:发表于2021-05-23 10:20 被阅读0次

    Flutter中私有组件可以管理自身状态,当需要跨组件管理状态时可以用到InheritedWidget,InheritedWidget可以共享数据,数据传递方式从上往下,它的子组件都可以获取InheritedWidget中的数据,实现了跨组件传递。
    如组件B和C都是对应的子组件,当B去修改共享数据时,C可以同时获取到修改完后的数据。同时还有一个特性,当父组件rebuild的时间,会触发子组件的didChangeDependencies,前提是子组件要用到父组件的共享数据,在获取父组件的共享数据时,子组件会被注册,从而可以使didChangeDependencies产生依赖关系。
    updateShouldNotify方法决定子组件的didChangeDependencies是否调用

    import 'package:flu_demo/share_data.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class Model {
      int num;
      Model(this.num);
    }
    
    //共享数据
    class ShareDataWidget extends InheritedWidget {
      late final int data;
      final Model model;
      ShareDataWidget(this.data, this.model, child) : super(child: child);
    
      @override
      bool updateShouldNotify(covariant ShareDataWidget oldWidget) {
        // TODO: implement updateShouldNotify
        // return false;
        if (this.data != oldWidget.data) {
          var newData = this.data;
          var oldData = oldWidget.data;
          var newModel = this.model.num;
          var oldModel = oldWidget.model.num;
          print('this.data : $newData');
          print('oldWidget.data : $oldData');
          print('this.model : $newModel');
          print('oldWidget.model : $oldModel');
          return true;
        }
        return false;
      }
    
      static ShareDataWidget? of(BuildContext context) =>
          // context.getElementForInheritedWidgetOfExactType() as ShareDataWidget;
          context.dependOnInheritedWidgetOfExactType(aspect: ShareDataWidget);
    }
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key? key, required this.title}) : super(key: key);
      final String title;
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
      Model model = new Model(0);
    
      void _incrementCounter() {
        setState(() {
          _counter++;
          model.num++;
          print(_counter);
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          routes: {
            'share': (BuildContext context) => new ShareDataPage(),
          },
          home: Scaffold(
              appBar: AppBar(title: Text("第一个页面"),),
              body: Container(
                width: MediaQuery.of(context).size.width,
            color: Colors.white,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                SizedBox(
                  height: 80,
                ),
                SizedBox(
                    height: 60,
                    width: 120,
                    child: OutlinedButton(
                        onPressed: () => {_incrementCounter()},
                        child: Text('刷新父组件'))),
                Container(
                  color: Colors.white,
                  // 使用了inheritedWidget组件
                  child: ShareDataWidget(
                      _counter,
                      model,
                      Column(
                        children: [
                          SizedBox(
                            height: 60,
                          ),
                          Text('父组件数据:$_counter'),
                          _TestC(_counter),
                          _TestA(),
                          SizedBox(
                            height: 20,
                          ),
                          _TestB(),
                          SizedBox(
                            height: 20,
                          ),
                          RaisedButton(
                              child: Text("当前组件修改 model"),
                              //每点击一次,将count自增,然后重新build,ShareDataWidget的data将被更新
                              onPressed: () => {model.num++}),
                          SizedBox(
                            height: 20,
                          ),
                          RaisedButton(
                            child: Text("刷新UI 修改 countter"),
                            //每点击一次,将count自增,然后重新build,ShareDataWidget的data将被更新
                            onPressed: () => setState(() => _counter++),
                          ),
                          RaisedButton(
                            child: Text("跳转页面"),
                            onPressed: () => {
                              // Navigator.pushNamed(context, 'share')
                              Navigator.push(
                                  context,
                                  new MaterialPageRoute(
                                      builder: (context) =>
                                      ShareDataPage()))
                            },
                          ),
                        ],
                      )),
                ),
              ],
            ),
          )),
        );
      }
    }
    
    
    
    
    class _TestA extends StatefulWidget {
      @override
      __TestAState createState() => __TestAState();
    }
    
    class __TestAState extends State<_TestA> {
      @override
      Widget build(BuildContext context) {
        // 未使用
        // return Text('data');
        // 使用
        var m = ShareDataWidget.of(context);
        var num = m!.model.num;
        return Text('A的数据:$num');
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        //父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
        //如果build中没有依赖InheritedWidget,则此回调不会被调用。
        print("Dependencies change A");
      }
    }
    
    class _TestB extends StatefulWidget {
      @override
      __TestBState createState() => __TestBState();
    }
    
    class __TestBState extends State<_TestB> {
      @override
      Widget build(BuildContext context) {
        print("build B");
        var m = ShareDataWidget.of(context);
        var num = m!.model.num;
        return Column(
          children: [
            Text('B的数据: 1'),
            SizedBox(
              height: 20,
            ),
            RaisedButton(
              onPressed: () => setState(() => m.model.num++),
              child: Text("跨组件修改model"),
            ),
          ],
        );
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        //父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
        //如果build中没有依赖InheritedWidget,则此回调不会被调用。
        print("Dependencies change B");
      }
    }
    
    class _TestC extends StatefulWidget {
      final int count;
      _TestC(this.count);
    
      @override
      __TestCState createState() => __TestCState();
    }
    
    class __TestCState extends State<_TestC> {
      @override
      Widget build(BuildContext context) {
        var _count = widget.count;
        return Column(
          children: [
            Text('C的数据: $_count'), //
            SizedBox(
              height: 20,
            ),
          ],
        );
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        //父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
        //如果build中没有依赖InheritedWidget,则此回调不会被调用。
        // 没有使用InheritedWidget的数据 故不会被调用
        print("Dependencies change C");
      }
    }
    
    输出日志
    flutter: this.data : 15
    flutter: oldWidget.data : 14
    flutter: this.model : 28
    flutter: oldWidget.model : 28
    flutter: Dependencies change A
    flutter: Dependencies change B
    flutter: build B
    flutter: didChangeDependencies ShareDataPage
    
    

    跨组件修改数据时,共享数据会变更,不会rebuild,rebuild时还是需要调用父级setState,这样子组件都会rebuild,数据展示最新的更改后的值。
    当在父组件中加入model时,oldwidget和当前widget对应的model始终不变。原因不是很清楚,可能是model创建后地址不变,新旧widget始终指向该地址。

    image.png

    相关文章

      网友评论

          本文标题:InheritedWidget 共享数据组件

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