前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[- Flutter 数据&状态篇 -] InheritedWidget

[- Flutter 数据&状态篇 -] InheritedWidget

作者头像
张风捷特烈
发布2020-04-30 15:17:04
3340
发布2020-04-30 15:17:04
举报

一个界面是由众多组件拼组而成。经常需要将一个组件进行封装,但此时有一个问题,如何让多个组件去共享一些值。

比如下面在一个_State中使用了WidgetA组件,传入_incrementCounter自加的方法和_counter计数值。 WidgetA又是由下面若干个自定义的Widget组成。那么问题来了,WidgetK点击时如何让WidgetE中的值+1? 一个最直接的方法就是通过构造函数将变量和函数一层层向下传递。你也许会说WTF,你好像在逗我笑?


1.现在来模拟一下这个情景

将计数器的页面分成五个部分,分别用一个Widget来控制。

代码语言:javascript
复制
WidgetA:控制视图总体显示   依赖WidgetB和WidgetF
WidgetB:控制视图布局排布   依赖WidgetC
WidgetC:控制视图内容组成   依赖WidgetD
WidgetD:控制视图计数器使用
WidgetF:控制视图触发计数

现在要让WidgetF的点击被WidgetD响应,下面是最笨的解决方案:构造传参,一层层传递。虽然麻烦,但又不是不能用。

代码语言:javascript
复制
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  @override
  Widget build(BuildContext context) {
    return WidgetA(_counter,_incrementCounter,widget.title);
  }
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
}

class WidgetA extends StatelessWidget {
  WidgetA(this.counter,this.increment,this.title);
  final int counter;
  final VoidCallback increment;
  final String title;
  @override
  Widget build(BuildContext context) {
    var result= Scaffold(
      appBar: AppBar(title: Text(title),),
      body: WidgetB(counter),
      floatingActionButton: WidgetF(increment),
    );
    return result;
  }
}

class WidgetB extends StatelessWidget {
  WidgetB(this.counter);
  final int counter;
  @override
  Widget build(BuildContext context) {
    var center= Center(
      child: WidgetC(counter),
    );
    return center;
  }
}

class WidgetC extends StatelessWidget {
  WidgetC(this.counter);
  final int counter;
  @override
  Widget build(BuildContext context) {
    var column=Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text('You have pushed the button this many times:',),
        WidgetD(counter)
      ],
    );
    return column;
  }
}

class WidgetD extends StatelessWidget {
  WidgetD(this.counter);
  final int counter;
  @override
  Widget build(BuildContext context) {
    var text= Text('$counter', style: Theme.of(context).textTheme.display1,);
    return text;
  }
}

class WidgetF extends StatelessWidget {
  WidgetF(this.increment);
  final VoidCallback increment;
  @override
  Widget build(BuildContext context) {
    var button= FloatingActionButton(
      onPressed: increment,
      tooltip: 'Increment',
      child: Icon(Icons.add),
    );
    return button;
  }
}
复制代码

是不是感觉非常麻烦呢? 如何处理这种情况,能让需要的参数不这么跋山涉水?


2.第一个解决方案:InheritedWidget

这里我们使用一个InheritedWidget来提供数据和方法,让她们共享与五个组件之中。就像下面这样,将值存储于一个InheritedWidget中,随用随取。这样世界终于清静了,不用构造传值满天飞。

代码语言:javascript
复制
/// 数据模型
class CountModel {
  final int count;//计数器
  final VoidCallback increment;//增长函数
  const CountModel(this.count,this.increment);
}

class CountWidget extends InheritedWidget {
  final CountModel model;
  CountWidget({
    Key key,
    @required this.model,
    @required Widget child,
  }) : super(key: key, child: child);

  static CountWidget of(BuildContext context) {//提供数据模型方法
    return context.inheritFromWidgetOfExactType(CountWidget);
  }

  //是否重建widget就取决于数据是否相同
  @override
  bool updateShouldNotify(CountWidget oldWidget) {
    return model.count != oldWidget.model.count;
  }
}

再看一下现在每个子组件的实现,就无需把需要的参数一层层往下传。 如果你的封装层级较深,InheritedWidget将是你数据传递的好帮手。

代码语言:javascript
复制
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;

  @override
  Widget build(BuildContext context) {
    return
      CountWidget(child:  WidgetA(widget.title),model: CountModel(_counter, _incrementCounter),);
  }

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
}

class WidgetA extends StatelessWidget {
  WidgetA(this.title);
  final String title;
  @override
  Widget build(BuildContext context) {
    var result= Scaffold(
      appBar: AppBar(title: Text(title),),
      body: WidgetB(),
      floatingActionButton: WidgetF(),
    );
    return result;
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var center= Center(
      child: WidgetC(),
    );
    return center;
  }
}

class WidgetC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var column=Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text('You have pushed the button this many times:',),
        WidgetD()
      ],
    );
    return column;
  }
}

class WidgetD extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var counter= CountWidget.of(context).model.count;
    var text= Text('$counter', style: Theme.of(context).textTheme.display1,);
    return text;
  }
}

class WidgetF extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var increment= CountWidget.of(context).model.increment;
    var button= FloatingActionButton(
      onPressed: increment,
      tooltip: 'Increment',
      child: Icon(Icons.add),
    );
    return button;
  }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年08月18日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.现在来模拟一下这个情景
  • 2.第一个解决方案:InheritedWidget
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档