美文网首页
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