嵌套层级深的问题让众多刚接触Flutter的同窗感到困扰,它不只是看起来让人感到不适,还很是影响编码体验。git
大佬们会告诉你应该拆分本身的嵌套代码(自定义widget或者抽取build方法)来减小嵌套层级。这确实是个行之有效的方法,除此以外,还有没有别的方法呢,本文将向您介绍另外一种减小嵌套层级的方法。github
嵌套过深影响代码的视觉观感面试
这段代码演示了什么叫作:编程
嵌套地狱架构
class Test extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Demo'),), body: Container( child: Offstage( offstage: false, child: ListView( children: <Widget>[ Container( color: Colors.white, padding: EdgeInsets.all(20), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Icon(Icons.phone), Text("amy"), ], ), ), Container( color: Colors.white, padding: EdgeInsets.all(20), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Icon(Icons.phone), Text("billy"), ], ), ), ], ), ), ), ); } } Thread thread = new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Toast.makeText(MainActivity.this,"子线程弹出Toast",Toast.LENGTH_SHORT).show(); Looper.loop(); } }); thread.start();
提取build方法后,嵌套层级获得了明显的改善:app
class Test extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Demo'),), body: Container( child: Offstage( offstage: false, child: ListView( children: <Widget>[ buildItem("amy"), buildItem("billy"), ], ), ), ), ); } Container buildItem(String name) { return Container( color: Colors.white, padding: EdgeInsets.all(20), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Icon(Icons.phone), Text(name), ], ), ); } }
还能不能继续优化呢?less
举个例子:ide
想要给下面这段代码中的第2个Textwidget加上marginTop:10属性函数
@override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(10), child: Column( children: <Widget>[ Text('billy'), Text('say hello'), //add margin top?? ], ), ); }
此时,我心里但愿能够这样写:oop
显然,flutter不支持这么写,幸运的是:dart2.7发布时正式宣布支持扩展函数(Extension Methods)
https://medium.com/dartlang/d...
实际上从dart 2.6.0就开始支持扩展函数了 若是pubspec.yaml中设置的dart版本低于2.6.0则会出现警告提示 如: environment: sdk: ">=2.1.0 <3.0.0" 警告提示: Extension methods weren’t supported until version 2.6.0
先来定义一个扩展函数
extension WidgetExt on Widget { Container intoContainer({ //复制Container构造函数的全部参数(除了child字段) Key key, AlignmentGeometry alignment, EdgeInsetsGeometry padding, Color color, Decoration decoration, Decoration foregroundDecoration, double width, double height, BoxConstraints constraints, EdgeInsetsGeometry margin, Matrix4 transform, }) { //调用Container的构造函数,并将当前widget对象做为child参数 return Container( key: key, alignment: alignment, padding: padding, color: color, decoration: decoration, foregroundDecoration: foregroundDecoration, width: width, height: height, constraints: constraints, margin: margin, transform: transform, child: this, ); } }
如今,全部widget对象都多了一个intoContainer(...)扩展函数,并且参数与Container构造方法一致,因而,咱们就能够这样写了:
除了Container,其它容器也能够经过一样的方式来扩展。因而,编程体验大大提高。
还能够支持链式调用:
Text("billy") .intoExpanded(flex: 1) .intoContainer(color: Colors.white)
有些widget有多个子widget (children), 能够添加以下的扩展函数:
extension WidgetExt on Widget { //添加一个相邻的widget,返回List<Widget> List<Widget> addNeighbor(Widget widget) { return <Widget>[this, widget]; } //添加各类单child的widget容器 //如:Container、Padding等... } extension WidgetListExt<T extends Widget> on List<T> { //子List<Widget>列表中再添加一个相邻的widget,并返回当前列表 List<Widget> addNeighbor(Widget widget) { return this..add(widget); } Row intoRow({ Key key, MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, MainAxisSize mainAxisSize = MainAxisSize.max, CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, TextDirection textDirection, VerticalDirection verticalDirection = VerticalDirection.down, TextBaseline textBaseline, }) { return Row( key: key, mainAxisAlignment: mainAxisAlignment, mainAxisSize: mainAxisSize, crossAxisAlignment: crossAxisAlignment, textDirection: textDirection, verticalDirection: verticalDirection, textBaseline: textBaseline, children: this, ); } //添加其它多child的widget容器 //如:Column、ListView等... }
回到本文最初的嵌套地狱,如今咱们的代码能够写成这样
class Test extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Demo'),), body: buildItem("amy") .addNeighbor(buildItem("billy"),) .intoListView() .intoOffstage(offstage: false) .intoContainer() ); } Container buildItem(String name) { return Icon(Icons.phone) .addNeighbor(Text(name)) .intoRow(crossAxisAlignment: CrossAxisAlignment.center,) .intoContainer(color: Colors.white, padding: EdgeInsets.all(20),); } }
为了让咱们的代码更加符合链式编程风格,再定义一个静态方法吧
class WidgetChain { static Widget addNeighbor(Widget widget) { return widget; } }
另外,再定义一个从数据到widget的映射扩展方法
extension ListExt<T> on List<T> { List<Widget> buildAllAsWidget(Widget Function(T) builder) { return this.map<Widget>((item) { return builder(item); }).toList(); } } class WidgetChain { static Widget addNeighbor(Widget widget) { return widget; } }
如今,代码是这样的:
class Test extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Demo'),), body: ["amy", "billy"] .buildAllAsWidget((name) => WidgetChain .addNeighbor(Icon(Icons.phone)) .addNeighbor(Text(name)) .intoRow(crossAxisAlignment: CrossAxisAlignment.center,) .intoContainer(color: Colors.white, padding: EdgeInsets.all(20),) ) .intoListView() .intoOffstage(offstage: false) .intoContainer() ); } }
值得指出的是,扩展函数(无嵌套)跟构造函数(有嵌套)是能够混用的。
上面的代码也能够写成这样(Container和Offstage这2层改为了构造函数):
class Test extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Demo'),), body: Container( child: Offstage( offstage: false, child: ["amy", "billy"] .buildAllAsWidget((name) => WidgetChain .addNeighbor(Icon(Icons.phone)) .addNeighbor(Text(name)) .intoRow(crossAxisAlignment: CrossAxisAlignment.center,) .intoContainer(color: Colors.white, padding: EdgeInsets.all(20),) ) .intoListView() ), ), ); } }
这样的扩展函数你想不想试试呢?
我已经替你们封装好了经常使用Widget对应的into扩展函数,能够直接食用:
dependencies: widget_chain: ^0.1.0
导入:
import 'package:widget_chain/widget_chain.dart';
而后就能够起飞了!
Github源码地址:
https://github.com/luckybilly...
就算你如今用不上,也能够先star收藏之,从此若是有人向你吐槽flutter嵌套深,除了叫他拆分封装以外,还能够把widget_chain甩给他 :D
本文介绍了Flutter中的嵌套地狱,并使用扩展函数的方式来解决flutter的嵌套地狱问题。
因为大篇幅的扩展函数调用会影响代码的阅读体验(由于intoXxx函数的调用顺序与widget层级是相反的),须要保留关键嵌套层级结构以使得布局的层级结构保持清晰,文中的扩展函数支持与构造函数混用,具体使用到什么程度,就看你们本身的选择了。
本文初次发布时包含了使用扩展函数提高编码体验的相关内容。
由于我以前编写flutter代码时添加父容器的方式为:
后来经大佬告知我:IDE中其实提供了添加父容器的快捷键(光标定位在Widget上,而后Alt + Enter,选择须要添加的父容器便可),很是方便。
以前我确实不知道,特别感谢大佬!
因而,从新编辑了本文,重点介绍如何使用扩展函数以不同的编码风格来解决flutter嵌套层级过深的问题。
但愿你们喜欢!
在这我也分享一份本身收录整理的 Android学习PDF+架构视频+面试文档+源码笔记 ,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅的精品资料
总之也是在这里帮助你们学习提高进阶,也节省你们在网上搜索资料的时间来学习,也能够分享给身边好友一块儿学习
若是你有须要的话,能够点赞+评论,关注我, 加Vx:15388039515(备注思否,须要资料)