Flutter嵌套深?扩展函数了解一下

背景

嵌套层级深的问题让众多刚接触Flutter的同学感到困扰,它不仅是看起来让人感到不适,还非常影响编码体验。

大佬们会告诉你应该拆分自己的嵌套代码(自定义widget或者抽取build方法)来减少嵌套层级。这确实是个行之有效的方法,除此之外,还有没有别的方法呢,本文将向您介绍另一种减少嵌套层级的方法。

嵌套过深影响代码的视觉观感

这段代码演示了什么叫做:嵌套地狱

class Test extends StatelessWidget {@overrideWidget 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"),],),),],),),),);}
}

提取build方法后,嵌套层级得到了明显的改善

class Test extends StatelessWidget {@overrideWidget 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),],),);}
}

还能不能继续优化呢?

自定义扩展函数

举个例子:想要给下面这段代码中的第2个Textwidget加上marginTop:10属性

  @overrideWidget build(BuildContext context) {return Container(padding: EdgeInsets.all(10),child: Column(children: <Widget>[Text('billy'),Text('say hello'), //add margin top??],),);}

此时,我内心希望可以这样写:

添加marginTop1

显然,flutter不支持这么写,幸运的是:dart2.7发布时正式宣布支持扩展函数(Extension Methods)

实际上从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构造方法一致,于是,我们就可以这样写了:

添加marginTop1

除了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 {@overrideWidget 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 Test extends StatelessWidget {@overrideWidget 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());}
}

值得指出的是,扩展函数(无嵌套)跟构造函数(有嵌套)是可以混用的。上面的代码也可以写成这样(ContainerOffstage这2层改成了构造函数):

class Test extends StatelessWidget {@overrideWidget 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源码地址: widget_chain 敬请star收藏

总结

本文介绍了Flutter中的嵌套地狱,并使用扩展函数的方式来解决flutter的嵌套地狱问题。

由于大篇幅的扩展函数调用会影响代码阅读体验,还是需要保留部分关键嵌套层级结构以使得布局的层级结构保持清晰,文中的扩展函数支持与构造函数混用,具体使用到什么程度,就看大家自己的选择了


原文链接
本文为阿里云原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/517067.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS Code 中的文件添加图标的插件vscode-icons

文章目录1. 效果图2. 用法1. 效果图 2. 用法 一旦你安装了该插件你重启VS Code后会在右下角收到一个该插件的提示&#xff0c;这时你要点击Activate激活icons。 你也可以通过点击以下功能来激活它(VS Code中可能存在很多主题&#xff0c;想用哪个就激活哪个)。 Linux & W…

开发者说:如何使用插件降低上传文件部署服务的复杂度

“ 这里描述我们实际服务部署的时候频繁发生的两个常用场景。 第一个场景&#xff0c;我们“办公网环境”想要在“准生产环境”下部署&#xff0c;需要做如下工作&#xff1a; 打包、将文件上传到堡垒机上、scp将上传好的包裹传输到“准生产环境”的目标机器、ssh 目标机器、r…

打开通往新零售时代的大门,数据中台这把钥匙可行吗?

2016年“新零售”概念提出即被引爆&#xff0c;如今看来依然让人热血沸腾&#xff0c;因为这三个字&#xff0c;极有可能影响未来十年、二十年的商业格局。在新零售概念下&#xff0c;大数据技术可以在任何时间和地点无形地收集和沉淀客户的主要行为数据&#xff0c;直接掌握客…

Vue+mui实现图片的本地缓存

效果&#xff1a; const menu {state: {products: {},GLOBAL_CONFIG:GLOBAL_CONFIG[GLOBAL_CONFIG]},mutations: {get_product: function (state, products) {//商品列表state.products products;for(let i 0; i < state.products.length; i){if(state.products[i][image…

年度回顾 | 2019 年的 Apache Flink

2019 年即将落下帷幕&#xff0c;这一年对于 Apache Flink 来说是非常精彩的一年&#xff0c;里程碑式的一年。随着这一年在邮件列表发送了超过 1 万封邮件&#xff0c;JIRA 中超过 4 千个 tickets&#xff0c;以及 GitHub 上超过 3 千个 PR&#xff0c;Apache Flink 迎来了快速…

VS Code 报错Vetur can‘t find ‘tsconfig.json‘ or ‘jsconfig.json‘的解决方法

文章目录一、原因二、说明三、显式项目四、解决方法&#xff08;3选1&#xff09;4.1. 配置Vetur插件&#xff0c;忽略提示4.2.在项目根目录创建jsconfig.json文件4.3.在项目根目录创建vetur.config.js文件一、原因 Vetur 0.31.0版本新增了一个vetur.config.js的配置文件&…

IDE 插件新版本发布,总有一个功能帮到你——开发部署提速 8 倍

对于开发者而言&#xff0c;提高工作效率大概有 2 种主要方式&#xff0c;第一种方式就是加快自己的工作速度&#xff0c;争取在同一段时间内多码一些代码、多干一些活来实现多产&#xff1b;而聪明的开发者会选择第二种方式&#xff0c;就是通过插件&#xff0c;让一些重复性的…

推特惊爆史诗级漏洞,App 恶意窃取用户隐私,云端安全路向何方?

作者 | 马超来源 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;近日&#xff0c;全球安全事件频发&#xff0c;先是推特惊爆史诗级漏洞&#xff0c;黑客对推特进行比特币钓鱼骗局&#xff0c;获取了对包括美国前总统奥巴马、钢铁侠埃隆马斯克、和世界首富比尔盖茨推特…

读懂这本书,才算读懂阿里大数据

2019年&#xff0c;是阿里巴巴第11个双11。众所周知&#xff0c;阿里的电商在线体系经过多年发展&#xff0c;可以支持峰值超过每秒50几万笔交易。但鲜有人知的是&#xff0c;海量的交易&#xff0c;创造了海量的数据&#xff0c;爆炸性的数据量激增&#xff0c;给狂欢过后的大…

Vue封装预约日期插件和发布到npm上

插件代码 <template><div class"subscribe-time" v-show"setting.display"><div class"subscribe-content"><div class"subscribe-date" v-if"setting.dateBlock true"><div class"subsc…

VS Code Element 提示 VSCode-Element-Helper 插件

文章目录1. 安装插件2. 效果图1. 安装插件 2. 效果图

9张图总结一下阿里云的2019

9月25日云栖大会&#xff0c;阿里云智能总裁张建锋展示了阿里巴巴第一颗自研芯片——含光800&#xff0c;打破了两项世界纪录&#xff0c;性能和能效比均为第一&#xff0c;是全球最强的AI推理芯片。 张建锋说&#xff1a;“在全球芯片领域&#xff0c;阿里巴巴是一个新人&…

坦白讲!做 Java 工程师,挺好!

很多想要入行编程圈的人问到我该学哪一种语言&#xff0c;我都毫不犹豫的说Java。首先我们先看个排行榜&#xff0c;来自权威开发语言排行榜TIOBE的数据&#xff08;截止到2020年4月&#xff09;&#xff0c;可以看到Java语言依然在语言排行榜霸占第一的位置&#xff01;看到这…

达摩院2020十大科技趋势发布:科技浪潮新十年序幕开启

2020年第一个工作日&#xff0c;“达摩院2020十大科技趋势”发布。这是继2019年之后&#xff0c;阿里巴巴达摩院第二次预测年度科技趋势。 回望2019年的科技领域&#xff0c;静水流深之下仍有暗潮涌动。AI芯片崛起、智能城市诞生、5G催生全新应用场景……达摩院去年预测的科技…

VS Code Rainbow Fart 小姐姐语音提示插件

文章目录1. 安装插件2. 启用Rainbow Fart3. 效果图1. 安装插件 Rainbow Fart2. 启用Rainbow Fart ctrl shirt p输入Rainbow Fart回车&#xff08;Enter&#xff09; 打开open 3. 效果图

日志服务(SLS)集成 Spark 流计算实战

前言 日志服务作为一站式的日志的采集与分析平台&#xff0c;提供了各种用户场景的日志采集能力&#xff0c;通过日志服务提供的各种与与SDK&#xff0c;采集客户端&#xff08;Logtail&#xff09;&#xff0c;Producer&#xff0c;用户可以非常容易的把各种数据源中的数据采…

再见了,Python!!

结合我最近这些年的Python学习、开发经验&#xff0c;发现90%的人在学Python时都会遇到下面这些问题&#xff1a;1.想学Python&#xff0c;但没什么经验根本不知道从何学起&#xff0c;而且应用方向太多了根本不知道该选择什么方向...2.基础入门看似简单&#xff0c;但是进阶实…

上去很美的 Serverless 在中国落地的怎么样了?

说起当前最火的技术&#xff0c;不得不提的一个概念就是 Serverless。2019 年几乎所有人都在说 Serverless&#xff0c;实际落地 Serverless 的有多少&#xff1f;Serverless 作为一种新型的互联网架构&#xff0c;直接或间接推动了云计算的发展&#xff0c;从 AWS Lambda 到阿…

Knative 驾驭篇:带你 '纵横驰骋' Knative 自动扩缩容实现

Knative 中提供了自动扩缩容灵活的实现机制&#xff0c;本文从 三横两纵 的维度带你深入了解 KPA 自动扩缩容的实现机制。让你轻松驾驭 Knative 自动扩缩容。 注&#xff1a;本文基于最新 Knative v0.11.0 版本代码解读 KPA 实现流程图 在 Knative 中&#xff0c;创建一个 Rev…

MongoDB 计划从“Data Sprawl”中逃脱

原文作者 | Adrian Bridgwater译者 |天道酬勤&#xff0c;责编 |晋兆雨头图 | CSDN 付费下载自视觉中国提供特定技术子集的软件供应商&#xff0c;喜欢用尽可能广泛的标签来提升自己&#xff0c;这是一种传达平台宽度和能力的方式。我们知道MongoDB以开源根数据库而闻名&#x…