Flutter发布到现在最让人吐槽的就是它的布局嵌套的写法,复杂布局嵌套层数多,导致代码阅读困难。其实如安卓与html语言布局代码也是嵌套的,不同的是它们把布局写到了单独的文件。
本文分享一些避免Flutter的UI代码嵌套太深和优化代码的方式。如果对本文内容或观点有相关疑问,欢迎在评论中指出。
一、最常见的嵌套布局优化,举个例子进行优化
//优化前
//左边一张图片,右边一些文本
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(child: Image.asset("xxx.png"),width: 100,height: 100),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 16),
child: DefaultTextStyle(
style: TextStyle(color: Colors.pink, fontSize: 16),
child: Column(
children: [
Text("11111"),
Text("22222"),
Text("33333"),
],
),
),
)
],
);
- 拆分方法优化(注意:build ui方法嵌套不得超过2层,超过两层请抽成小组件类,或者用上面的方式优化)
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [_buildRight(),_buildLift()],
//_buildLift() 后面写不写","很重要,写了会换行显示,开发中看代码长度决定
);
}
_buildLift() => Container(child: Image.asset("xxx.png"), color: Colors.amber, width: 100, height: 100);
_buildRight() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 16),
//_buildTexts()这边后面加了","换行显示更美观
child: _buildTexts(),
);
}
//已经到第二层了,如果还要抽成方法建议单独写组件
_buildTexts() {
DefaultTextStyle(
style: TextStyle(color: Colors.pink, fontSize: 16),
child: Column(children: [Text("11111"), Text("22222"), Text("33333")]),
);
}
- 使用局部变量优化(在Flutter源码中经常可以看的,如:Container())
Widget build(BuildContext context) {
return Scaffold(body: _buildItem());
}
_buildItem() {
final left = Container(child: Image.asset("xxx.png"), width: 100, height: 100);
Widget right = Column(children: [Text("11111"), Text("22222"), Text("33333")]);
right = DefaultTextStyle(style: TextStyle(color: Colors.pink, fontSize: 16), child: right);
right = Padding(padding: EdgeInsets.symmetric(horizontal: 10, vertical: 16), child: right);
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [left, right],
);
}
- 使用扩展函数,这是我写的一个扩展函数库flu_ext
Widget build(BuildContext context) {
return Scaffold(
body: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset("xxx.png").container(width: 100, height: 100),
Widgets.addWidget(Text("11111"))
.addWidget(Text("2222"))
.addWidget(Text("33333"))
.intoColumn()
.defaultTextStyle(style: TextStyle(color: Colors.pink, fontSize: 16))
.padding(padding: EdgeInsets.symmetric(horizontal: 10, vertical: 16)),
],
),
);
二、使用"...","if","for"优化,写布局难免会涉及到布局隐藏、动态添加等,举个例子进行优化
//优化前
//1.在一个listview里面显示一个banner
//2.通过判断显示按钮
//3.通过判断显示三个文本
//4.显示三个icon
//5.通过判断把String数组显示到界面上
@override
Widget build(BuildContext context) {
bool isShowButton = false;
bool isShowArr = true;
const arr = ["第一个", "第二个", "第三个"];
List list = [
//1.Banner
_buildBanner(),
//2.用三元符控制按钮显示与隐藏,会多渲染
isShowButton ? FlatButton(onPressed: _onPressed, child: Text("按钮")) : SizedBox(),
];
//3.用bool变量控制显示数组
if (isShowArr) {
list.addAll([Text("安卓"), Text("IOS"), Text("Flutter")]);
}
//4.添加数组
list.addAll(_buildIcons());
//5.用bool变量控制显示数组
if (isShowArr) {
list.addAll(arr.map((e) => Text(e)).toList());
}
return Scaffold(
body: ListView(children: list),
);
}
_buildBanner() => Container(height: 100, width: double.infinity, color: Colors.amberAccent);
List _buildIcons() {
return [Icon(Icons.android, size: 30), Icon(Icons.home, size: 30), Icon(Icons.person_rounded, size: 30)];
}
优化后
Widget build(BuildContext context) {
bool isShowButton = false;
bool isShowArr = true;
const arr = ["第一个", "第二个", "第三个"];
return Scaffold(
body: ListView(
children: [
//1.Banner
_buildBanner(),
//2.用bool变量控制按钮显示与隐藏
if (isShowButton) FlatButton(onPressed: _onPressed, child: Text("按钮")),
//3.用bool变量控制显示数组,用...添加数组或集合
if (isShowArr) ...[Text("安卓"), Text("IOS"), Text("Flutter")],
//4.用...添加数组或集合
..._buildIcons(),
//5.用bool变量控制显示数组,用for循环展示
if (isShowArr)
for (var value in arr) Text(value),
],
),
);
}
_buildBanner() => Container(height: 100, width: double.infinity, color: Colors.amberAccent);
List _buildIcons() {
return [Icon(Icons.android, size: 30), Icon(Icons.home, size: 30), Icon(Icons.person_rounded, size: 30)];
}
_onPressed() {}
三、最后通过命名构造降低使用难度,适用于复用界面
///优化前
///一个游戏商店,有三个角色,vip,游戏管理员,普通用户(普通用户分有没有钱)
///创建vip界面
GameStorePage(isVip: true);
///创建普通用户没钱界面
GameStorePage(isVip: false);
///创建普通用户有钱界面
GameStorePage(isVip: false,isHaveMoney: true);
///创建GM界面
GameStorePage(isGM: true);
///这种创建方式需要使用者必须了解多种参数的组合
class GameStorePage extends StatelessWidget {
final bool isVip;
final bool isHaveMoney;
final bool isGM;
//写const可以优化内存
const GameStorePage({Key key, this.isVip = false, this.isHaveMoney = false, this.isGM = false})
: super(key: key);
@override
Widget build(BuildContext context) {
return ListView(
children: [
if (isVip || isGM) _buildVipUI(), //vip界面
if (!isVip && !isGM) _buildNormalUI(), //普通用户界面
if (isGM) _buildEditGoodsButton(), //GM可以编辑商品
if (isVip || isHaveMoney) _buildPayButton(), //vip和有钱的用户可以直接支付
],
);
}
//........代码省略
}
优化后
///一个游戏商店,有三个角色,vip,游戏管理员,普通用户(普通用户分有没有钱)
///创建vip界面
GameStorePage.vip();
///创建普通用户没钱界面
GameStorePage.normal();
///创建普通用户有钱界面
GameStorePage.normal(isHaveMoney:true);
///创建GM界面
GameStorePage.gm();
///这种创建方式屏蔽内部细节,使用简单
class GameStorePage extends StatelessWidget {
final bool isVip;
final bool isHaveMoney;
final bool isGM;
//写const可以优化内存
const GameStorePage.vip({Key key}):isGM=false,isHaveMoney=false,isVip=true,super(key: key);
const GameStorePage.normal({Key key,this.isHaveMoney=false}):isGM=false,isVip=false,super(key: key);
const GameStorePage.gm({Key key}):isGM=true,isHaveMoney=false,isVip=false,super(key: key);
@override
Widget build(BuildContext context) {
return ListView(
children: [
if (isVip || isGM) _buildVipUI(), //vip界面
if (!isVip && !isGM) _buildNormalUI(), //普通用户界面
if (isGM) _buildEditGoodsButton(), //GM可以编辑商品
if (isVip || isHaveMoney) _buildPayButton(), //vip和有钱的用户可以直接支付
],
);
}
//........代码省略
}