InheritedWidget 共享數(shù)據(jù)組件

Flutter中私有組件可以管理自身狀態(tài),當(dāng)需要跨組件管理狀態(tài)時(shí)可以用到InheritedWidget,InheritedWidget可以共享數(shù)據(jù),數(shù)據(jù)傳遞方式從上往下,它的子組件都可以獲取InheritedWidget中的數(shù)據(jù),實(shí)現(xiàn)了跨組件傳遞。
如組件B和C都是對應(yīng)的子組件,當(dāng)B去修改共享數(shù)據(jù)時(shí),C可以同時(shí)獲取到修改完后的數(shù)據(jù)。同時(shí)還有一個(gè)特性,當(dāng)父組件rebuild的時(shí)間,會觸發(fā)子組件的didChangeDependencies,前提是子組件要用到父組件的共享數(shù)據(jù),在獲取父組件的共享數(shù)據(jù)時(shí),子組件會被注冊,從而可以使didChangeDependencies產(chǎn)生依賴關(guān)系。
updateShouldNotify方法決定子組件的didChangeDependencies是否調(diào)用

import 'package:flu_demo/share_data.dart';
import 'package:flutter/material.dart';

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

class Model {
  int num;
  Model(this.num);
}

//共享數(shù)據(jù)
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("第一個(gè)頁面"),),
          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('父組件數(shù)據(jù):$_counter'),
                      _TestC(_counter),
                      _TestA(),
                      SizedBox(
                        height: 20,
                      ),
                      _TestB(),
                      SizedBox(
                        height: 20,
                      ),
                      RaisedButton(
                          child: Text("當(dāng)前組件修改 model"),
                          //每點(diǎn)擊一次,將count自增,然后重新build,ShareDataWidget的data將被更新
                          onPressed: () => {model.num++}),
                      SizedBox(
                        height: 20,
                      ),
                      RaisedButton(
                        child: Text("刷新UI 修改 countter"),
                        //每點(diǎn)擊一次,將count自增,然后重新build,ShareDataWidget的data將被更新
                        onPressed: () => setState(() => _counter++),
                      ),
                      RaisedButton(
                        child: Text("跳轉(zhuǎn)頁面"),
                        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的數(shù)據(jù):$num');
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    //父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時(shí)會被調(diào)用。
    //如果build中沒有依賴InheritedWidget,則此回調(diào)不會被調(diào)用。
    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的數(shù)據(jù): 1'),
        SizedBox(
          height: 20,
        ),
        RaisedButton(
          onPressed: () => setState(() => m.model.num++),
          child: Text("跨組件修改model"),
        ),
      ],
    );
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    //父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時(shí)會被調(diào)用。
    //如果build中沒有依賴InheritedWidget,則此回調(diào)不會被調(diào)用。
    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的數(shù)據(jù): $_count'), //
        SizedBox(
          height: 20,
        ),
      ],
    );
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    //父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時(shí)會被調(diào)用。
    //如果build中沒有依賴InheritedWidget,則此回調(diào)不會被調(diào)用。
    // 沒有使用InheritedWidget的數(shù)據(jù) 故不會被調(diào)用
    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

跨組件修改數(shù)據(jù)時(shí),共享數(shù)據(jù)會變更,不會rebuild,rebuild時(shí)還是需要調(diào)用父級setState,這樣子組件都會rebuild,數(shù)據(jù)展示最新的更改后的值。
當(dāng)在父組件中加入model時(shí),oldwidget和當(dāng)前widget對應(yīng)的model始終不變。原因不是很清楚,可能是model創(chuàng)建后地址不變,新舊widget始終指向該地址。

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容