一个界面是由众多组件拼组而成。经常需要将一个组件进行封装,但此时有一个问题,如何让多个组件去共享一些值。
比如下面在一个_State中使用了WidgetA组件,传入_incrementCounter自加的方法和_counter计数值。
WidgetA又是由下面若干个自定义的Widget组成。那么问题来了,WidgetK点击时如何让WidgetE中的值+1?
一个最直接的方法就是通过构造函数将变量和函数一层层向下传递。你也许会说WTF,你好像在逗我笑?
1.现在来模拟一下这个情景
将计数器的页面分成五个部分,分别用一个Widget来控制。
WidgetA:控制视图总体显示 依赖WidgetB和WidgetF WidgetB:控制视图布局排布 依赖WidgetC WidgetC:控制视图内容组成 依赖WidgetD WidgetD:控制视图计数器使用 WidgetF:控制视图触发计数
现在要让WidgetF的点击被WidgetD响应,下面是最笨的解决方案:构造传参,一层层传递。虽然麻烦,但又不是不能用。
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中,随用随取。这样世界终于清静了,不用构造传值满天飞。
/// 数据模型 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; } }
class MyHomePage extends StatefulWidget {再看一下现在每个子组件的实现,就无需把需要的参数一层层往下传。
如果你的封装层级较深,InheritedWidget将是你数据传递的好帮手。
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;
}
}
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦