前言
首先我们知道Flutter的语法是嵌套型的,这种语法的最直观的感受就是代码多,嵌套层次深的话可能导致代码阅读困难,其实,这也是Flutter的一项不完美的地方吧。
正文
面对这个问题,我们可以采用代码抽取,复用的方式来减少在一个文件中堆叠大量代码;采用这种方式的好处如下:
- 减少了使用处代码的代码量和层级,代码精简直观
- 抽取出的代码可以多处复用,不限于当前页面,方便灵活拓展
- 减少了代码量的同时,也方便了后续维护者的阅读与编写,便于维护
一:代码抽取
在日常的开发中,我们首先会拿到UI的设计稿,在脑子里已经排版布局,然后就疯狂的码代码。例如UI小姐姐拿出了下面常用设计稿
我的
- 经过分析,这是一个除了图标和文字,其他都一样的组件
- 开始编写其中一条的代码,比如我的订单
- 写完一条后后粘贴复制,修改成其他剩余的icon和文字就搞定了
那我就直接拿出某一条代码,这是从Android studio里直接copy的,行数我看了下是41行,具体原始代码如下:
GestureDetector(
child: Container(
color: Color(0xffffffff),
padding: EdgeInsets.only(left: 20, right: 16),
child: SizedBox(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Wrap(
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
Image.asset(
"resource/imgs/icon_my_card.png",
width: 18,
height: 18,
fit: BoxFit.contain,
),
Padding(
padding: EdgeInsetsDirectional.only(start: 22)),
Text("银行卡01"),
],
),
Wrap(
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
Text(""),
Padding(
padding: EdgeInsetsDirectional.only(start: 10),
child:
Image.asset("resource/imgs/arrow_right.png"),
)
],
),
],
),
height: 48,
)),
onTap: () {},
)
按照我们原来的偷懒计划,直接粘贴复制,一顿操作后发现近300行代码,心中窃喜(这下统计代码量,老子吊打一切,- _-)。当然开玩笑,我们写代码不是为了多,而是完成一个功能,使用的代码越少越好。
二:改造代码,多处复用
我们上面发现,只是实现了7个相同的item,没有优化的情况下就编写了200多行代码,这实在是太多了,看起来也是眼花缭乱的。不行,我们作为有责任感,有逼格的程序员怎么能看的下去呢,我们需要对这坨代码进行优化,大脑在思考:
1. 其实大多数代码都一样,只是图标和文字不同
2. 是否能够抽取公共部分,把变量部分暴露出来给用户自己动态传递呢
答案当然是可以的,且思路也是正确的。那么我们用什么来存储这些公共部分呢,有两种方式:
1. 继承statelessWidget或者statefulWidget,重新渲染公共部分
2. 直接写个公共方法,在return里直接返回公共部分组件
两种方式都是可以的,看需求而定;如果你的公共部分不需要独立的动态渲染,只是提供静态的公共组件,那直接选用第二种将更方便;这里我们看,我们的公共部分,只是静态的显示,不涉及动态变化的东西,我们就直接用第二种,抽取的过程我就不多说了,下面看抽取出来的代码:
///通用item左右都带有有个icon和text的通用item,常用于我的页面等item条目
///
///[iconLeft] 左边icon的widget
///
///[textLeft] 左边文本的Widget
///
///[iconRight] 右边icon的widget
///
///[textRight] 右边文本的Widget
///
///[heightItem] item高度
///
///[paddingLeftRight] 左边Image距离右边文本的间距
///
///[paddingRightLeft] 右边Image距离左边文本的间距
///
///[importance] 左侧文本是否显示必填*号
///
///[onPress] item点击事件函数回调
iconTextItem(
{Widget iconLeft,
Widget iconRight,
double heightItem = 50,
double paddingLeftRight = 8,
double paddingRightLeft = 15,
importance = false,
Color backgroundColor,
double leftPadding,
double rightPadding,
@required Widget textLeft,
Widget textRight,
VoidCallback onPress,
Key key}) {
return GestureDetector(
child: Container(
key: key,
color: backgroundColor ?? Color(0xffffffff),
padding:
EdgeInsets.only(left: leftPadding ?? 0, right: rightPadding ?? 0),
child: SizedBox(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Wrap(
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
iconLeft ?? Text(""),
Padding(
padding: EdgeInsetsDirectional.only(
start: iconLeft != null ? paddingLeftRight : 0),
child:
importance ? _getImportanceText(textLeft) : textLeft),
],
),
Wrap(
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
textRight ?? Text(""),
Padding(
padding:
EdgeInsetsDirectional.only(start: paddingRightLeft),
child: iconRight ??
Image.asset("resource/imgs/arrow_right.png"),
)
],
),
],
),
height: heightItem,
)),
onTap: onPress,
);
}
/// 返回带有必填*的文本,*号默认红色
_getImportanceText(Text text, {Color color}) {
assert(text != null);
return Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
text,
Text(
"*",
style: TextStyle(color: color ?? colorRed23681731, fontSize: 15),
),
],
);
}
代码行数为59行,为啥反而多了呢,因为这里我又兼容了如下的设计稿,通过传入参数可以控制红色的*是否显示,也就是达到了是否必须的设计效果
必填项
那既然我们都封装好了,如何在代码里使用呢,使用方式在目标页面中,直接放入即可,具体引入处代码如下:
iconTextItem(
onPress: () {
print("我的银行卡");
Navigator.pushNamed(context, "/mybankcard");
},
leftPadding: 20,
rightPadding: 14,
// backgroundColor: Colors.greenAccent,
paddingLeftRight: 22,
iconLeft: Image.asset(
"resource/imgs/icon_my_card.png",
width: 18,
height: 18,
fit: BoxFit.contain,
),
textLeft: Text(
"我的银行卡",
style: TextStyle(color: colorBlackFF444C63, fontSize: 15),
),
)
我们把图标和文字声明在方法参数中,同时提供部分默认值,使用处传参即可。我复制过来是19行,原来41行,当前文件节省了21行,不仅如此还减少了层叠情况,看起来更清晰了。现在完成第一个设计稿只需要19*7=133行,比原来(42*7=294)优化了161行,这种效果还是看得见的
总结:
本片文章主要介绍了通过方法来抽取公共部分的代码加以复用,方便日后的维护拓展。这里还有个自己轻度封装简洁的库,是一个左右widget的package,同样可以达到上述效果,给用户留了更大的自定义空间,大家有兴趣的可以了解使用支持下
网友评论