Flutter UI代码优化

    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"),
                ],
              ),
            ),
          )
        ],
      );
  1. 拆分方法优化(注意: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")]),
    );
  }
  1. 使用局部变量优化(在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],
    );
  }
  1. 使用扩展函数,这是我写的一个扩展函数库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<Widget> 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<Widget> _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<Widget> _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和有钱的用户可以直接支付
      ],
    );
  }
//........代码省略
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容