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 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和有钱的用户可以直接支付
      ],
    );
  }
//........代码省略
}

你可能感兴趣的:(Flutter UI代码优化)