1. 程式人生 > >Flutter學習筆記(27)--資料共享(InheritedWidget)

Flutter學習筆記(27)--資料共享(InheritedWidget)

如需轉載,請註明出處: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回撥的!!!