Flutter學習筆記(27)–數據共享(InheritedWidget)

  • 2019 年 10 月 3 日
  • 筆記

如需轉載,請註明出處:Flutter學習筆記(27)–數據共享(InheritedWidget)

InheritedWidget是Flutter中非常重要的一個功能型組件,它提供了一種數據在widget樹中從上到下傳遞、共享的方式,比如我們在應用的根widget中通過InheritedWidget共享了一個數據,那麼我們便可以在任意子widget中來獲取該共享的數據。

前言:假設有這麼一個場景,A、B兩個組件,A組件有一個數據data,當A組件中的這個數據data發生變化後,B組件需要跟隨著做一些處理操作,這時候,如果不通過廣播或其他方式通知B組件,我們有什麼辦法實現這個功能呢?

didChangeDependencies

在State對象中,有一個didChangeDependencies回調,這個回調會在“依賴”發生變化時被Flutter Framework調用。而這個“依賴”指的是子widget是否用到了父widget中的InheritedWidget共享數據。如果使用了,則代表子widget依賴InheritedWidget,反之如果沒有使用則代表沒有依賴。這種機制可以使子組件在所依賴的InheritedWidget發生變化時來更新自身。這也就可以實現我們前面所假設的場景了!

接下來先給大家看一下整體的程式碼和效果截圖,心裡先有一個大概的概念,帶著幾個概念去思考:1.依賴 2.didChangeDependencies回調 3.InheritedWidge通過什麼來通知子widget 

import 'package:flutter/material.dart';    void main() => runApp(MyApp());    class FatherWidget extends InheritedWidget {    final int data;      FatherWidget({@required this.data, Widget child}) : super(child: child);      //子樹通過該方法獲取共享數據    static FatherWidget getData(BuildContext context) {      return context.inheritFromWidgetOfExactType(FatherWidget);    }      //該回調決定當data發生變化時,是否通知子樹中依賴data的widget    @override    bool updateShouldNotify(FatherWidget oldWidget) {      return oldWidget.data != data;    }  }    class ChildWidget extends StatefulWidget {    @override    _ChildWidgetState createState() => _ChildWidgetState();  }    class _ChildWidgetState extends State<ChildWidget> {    @override    Widget build(BuildContext context) {      return new Text(FatherWidget.getData(context).data.toString());    }      @override    void didChangeDependencies() {      super.didChangeDependencies();      //父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時會被調用      //如果build中沒有依賴InheritedWidget,則此回調不會被調用      print("didChangeDependencies = " +          FatherWidget.getData(context).data.toString());    }  }    class MyApp extends StatefulWidget {    @override    State<StatefulWidget> createState() {      return _MyAppState();    }  }    class _MyAppState extends State<MyApp> {    int count = 0;      @override    Widget build(BuildContext context) {      return new MaterialApp(        title: 'title',        home: new Scaffold(          appBar: new AppBar(            title: new Text('title'),          ),          body: new Center(            child: FatherWidget(              data: count,              child: new Column(                children: <Widget>[                  ChildWidget(),                  new FloatingActionButton(onPressed: _changeCount,child: new Icon(Icons.adjust),),                ],              ),            ),          ),        ),      );    }      _changeCount() {      setState(() {        ++count;        print('mCount == ' + count.toString());      });    }  }

 整體程式碼說明:

點擊按鈕後會調用_changeCount()方法,方法內給count數加1,然後通知框架重新build,重新build會給FatherWidget內的data重新賦值,data的數據發生了變化,updateShouldNotify會返回true,通知子widget執行didChangeDependencies回調來處理一下響應操作。

分塊說明一下實現數據共享都需要哪幾步:

1.用於存儲共享數據的父Widget,該widget繼承InheritedWidget

class FatherWidget extends InheritedWidget {    final int data;      FatherWidget({@required this.data, Widget child}) : super(child: child);      //子樹通過該方法獲取共享數據    static FatherWidget getData(BuildContext context) {      return context.inheritFromWidgetOfExactType(FatherWidget);    }      //該回調決定當data發生變化時,是否通知子樹中依賴data的widget    @override    bool updateShouldNotify(FatherWidget oldWidget) {      return oldWidget.data != data;    }  }

2.子widget,用來處理依賴發生變化時的響應處理操作didChangeDependencies

class ChildWidget extends StatefulWidget {    @override    _ChildWidgetState createState() => _ChildWidgetState();  }    class _ChildWidgetState extends State<ChildWidget> {    @override    Widget build(BuildContext context) {      return new Text(FatherWidget.getData(context).data.toString());    }      @override    void didChangeDependencies() {      super.didChangeDependencies();      //父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時會被調用      //如果build中沒有依賴InheritedWidget,則此回調不會被調用      print("didChangeDependencies = " +          FatherWidget.getData(context).data.toString());    }  }

3.FahterWidget和ChildWidget產生依賴關係

  //子樹通過該方法獲取共享數據    static FatherWidget getData(BuildContext context) {      return context.inheritFromWidgetOfExactType(FatherWidget);    }

 

4.數據更新,通過setState來重新build

class MyApp extends StatefulWidget {    @override    State<StatefulWidget> createState() {      return _MyAppState();    }  }    class _MyAppState extends State<MyApp> {    int count = 0;      @override    Widget build(BuildContext context) {      return new MaterialApp(        title: 'title',        home: new Scaffold(          appBar: new AppBar(            title: new Text('title'),          ),          body: new Center(            child: FatherWidget(              data: count,              child: new Column(                children: <Widget>[                  ChildWidget(),                  new FloatingActionButton(onPressed: _changeCount,child: new Icon(Icons.adjust),),                ],              ),            ),          ),        ),      );    }      _changeCount() {      setState(() {        ++count;        print('mCount == ' + count.toString());      });    }  }

 

最後需要注意一點,上面說到的依賴前提是兩個組件是父、子的關係,我試了一下,如果FatherWidget中沒有ChildWidget,只是單純的使用了FatherWidget的數據的話,是不會觸發didChangeDependencies回調的!!!