InhertedWidget和它的儿子们

0x00 概念介绍

简单一点说html

  • inhertedwidget 是一个widget,跟其余widget不同的地方是,他能够在他所持有的child中共享本身的数据。如Theme。
  • 应用场景:app的复杂度愈来愈大,对于数据之间的传递,若是都是根据dic或者model做为widget内部的参数传递,是不友好的方式。正常的想法,此时应该有个数据中心,或eventbus,用于数据传递和取用,而在flutter中是inhertwidget
  • 实现: 内部实现数据更新,自动通知的方式,从而自动刷新界面
  • 写法: 见下面例子

对于赶时间的同窗看到这里就能够回去搬砖了。下面留给还有五分钟时间浏览的同窗。数据库

google 在flutter widget of the week 中介绍 inheritedwidget, 短短的两个简短的视频,让人看到了flutter的用心,外语通常的我也能把概念看得个大概。可是对于真正使用其上手开发的同窗总以为离实际开发距离有点远,仍是得编写一下例子才能理解更深一点。api

做为一名高效的搬砖工,先看看它说了啥bash

0x01 前情提要

code4flutter

当应用变得更大时,小部件树,变得更复杂,传递和访问数据,会变得很麻烦。 若是你有四个或五个小部件一个接一个地嵌套, 而且您须要从顶部获取一些数据。将它添加到全部这些构造函数中,以及全部这些构建方法。网络

然而我只是想到达widget来获取数据。 不想一级一级传递数据。怎么办?幸运的是,有一个小部件类型容许这样。 它叫作InheritedWidget。app

inherted_notify

0x02 使用方式

建立一个InhertWidget

class FrogColor extends InheritedWidget {
  const FrogColor({
    Key key,
    @required this.color,
    @required Widget child,
  }) : assert(color != null),
       assert(child != null),
       super(key: key, child: child);

  final Color color;

  static FrogColor of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(FrogColor) as FrogColor;
  }

  @override
  bool updateShouldNotify(FrogColor old) => color != old.color;
}
复制代码

建立子WidgetA B

class TestWidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final inheritedContext = FrogColor.of(context);
    return new Padding(
        padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
        child: Container(
          color: inheritedContext.color,
          height: 100,
          width: 100,
          child: Text('第一个widget'),
        ));
  }
}


class TestWidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final inheritedContext = FrogColor.of(context);
    return new Padding(
        padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
        child: Container(
          color: inheritedContext.color,
          height: 50,
          width: 50,
          child: Text('第二个widget'),
        ));
  }
}
复制代码

建立带状态的widgetC

class TestWidgetC extends StatefulWidget {
  TestWidgetC({Key key}) : super(key: key);

  _TestWidgetCState createState() => _TestWidgetCState();
}

class _TestWidgetCState extends State<TestWidgetC> {
 

  @override
  Widget build(BuildContext context) {
     final inheritedContext = FrogColor.of(context);
    // print(" 重建c CCC ");
    return Container(
        child: Container(
      color: inheritedContext.color,
      height: 200,
      width: 200,
      child: prefix0.Column(
        children: <Widget>[
          Text("第三个widget"),        
        ],
      ),
    ));
  }

  @override
  void didChangeDependencies() {
    print(" 更改依赖 CCC ");
    super.didChangeDependencies();
  }
}
复制代码

组装

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  Color color = Color.fromARGB(0, 0xff, 0xdd, 0xdd);
  Color color2 = Color.fromARGB(0, 0xff, 0xdd, 0xdd);

  void _incrementCounter() {
    setState(() {
      _counter = (_counter + 20) % 255;
      Color color = Color.fromARGB(_counter, 0xff, 0xdd, 0xdd);
      this.color = color;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            new FrogColor(
              color: this.color,
              color2: this.color2,
              child: Column(
                children: <Widget>[
                  new TestWidgetA(),
                  new TestWidgetB(),
                  new TestWidgetC()
                ],
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

复制代码

本段代码实现了点击+号,数字增长,而且两个widget的颜色加深less

效果图以下ide

code4flutter

0x02 使用建议

InheritedWidgets一般包含一个名为的静态方法 of

它为您调用InheritWidget的精确类型方法。函数

static FrogColor of(BuildContext context) {
     return context.inheritFromWidgetOfExactType(FrogColor) as FrogColor;
   }
复制代码

final 不可变性

例子中FrogColor 里面的color就是一个final类型,不能够改变ui

只能替换InheritedWidget的字段,经过重建整个widget 树。 这个很重要!!! 只是意味着它没法从新分配。 可是并不意味着它不能在内部改变。

didChangeDependencies 改变时机

inhertedwidget改变了就会触发,didChangeDependencies,对于耗时操做的业务如网络请求来讲能够放置这里。

从上例中能够作个试验,在widgetC中移除 FrogColor.of(context) 这句话,能够看到,颜色很差随着按钮点击变色,另外也不会调用didChangeDependencies 这个方法了。可是widgetc仍是会走build方法。

能够印证两点,widget会重建,可是state不会重建,didChangeDespendice方法调用的时机是其依赖的上下文内容改变。

0x03 应用场景

  • Theme其实是一种InheritedWidget。 Scaffold,Focus Scope等等也是如此。

  • 附加服务对象到InheritedWidget。 如开发数据库的包装器

  • Web API的代理或资产提供者。 服务对象能够有本身的内部状态。 它能够启动网络呼叫,任何事情。

0x04 继承者们

老大,InheritedNotifier

继承自Inhertedwidget,其值能够是被监听的,而且只要值发送通知就会通知依赖者。

使用场景有 ChangeNotifierValueNotifier

abstract class InheritedNotifier<T extends Listenable> extends InheritedWidget {

  const InheritedNotifier({
    Key key,
    this.notifier,
    @required Widget child,
  }) : assert(child != null),
       super(key: key, child: child);
 
  @override
  bool updateShouldNotify(InheritedNotifier<T> oldWidget) {
    return oldWidget.notifier != notifier;
  }

  @override
  _InheritedNotifierElement<T> createElement() => _InheritedNotifierElement<T>(this);
}
复制代码

老二, InheritedModel

继承自 Inertedwidget的,容许客户端订阅值的子部分的更改。

就比InertedWidget多了一个必要方法updateShouldNotifyDependent,表示能够根据,部份内容的改变发送依赖变动通知。

class ABModel extends InheritedModel<String> {
  ABModel({this.a, this.b, Widget child}) : super(child: child);

  final int a;
  final int b;

  @override
  bool updateShouldNotify(ABModel old) {
    return a != old.a || b != old.b;
  }

  @override
  bool updateShouldNotifyDependent(ABModel old, Set<String> aspects) {
    return (a != old.a && aspects.contains('a')) ||
        (b != old.b && aspects.contains('b'));
  }
  // ...
}
复制代码

一图说明

inhertedmodel

参考

inhertedwidget 文档

原创不易,版权全部,转载请备注 code4flutter.com

相关文章
相关标签/搜索