V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zqlcrow
V2EX  ›  Flutter

Flutter 页面写的越整洁,越不能用 const,两难

  •  
  •   zqlcrow · 353 天前 · 2377 次点击
    这是一个创建于 353 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一直很困惑。

    比如说,一个页面有 4 个一样的元素,实现方式:

    1 、写个方法,接收 icon 和 text ,返回 Widget ,代码整齐美观。
    2 、直接复制粘贴 4 份 widget ,每个都是 const 。

    正常人的脑回路,应该都是 1.

    但曾经试过把一个 App ,所有能加 const 的地方全部加上,感觉效果是肉眼可见的。

    当然,最终的答案可能是平衡在哪里的问题。

    第 1 条附言  ·  353 天前

    方法1:

    const Row(
      children: ['aa', 'bb'].map(
             (e) => Image(
                   image: AssetImage(e),
                   fit: BoxFit.fill,
                   width: 20,
                   height: 20,
                   ),
             ).toList(),
    );
    

    或者

    const Row(
      children:[
        _getImage('xxxxx'),
        _getImage('yyyyy'),
       ],
    );  
    
    Widget _getImage(String asset){
      return Image(
             image: AssetImage(asset),
             fit: BoxFit.fill,
             width: 20,
             height: 20,
          );
    }
    

    方法2:

    const Row(
      children: [
         Image(
             image: AssetImage(xxxxx),
             fit: BoxFit.fill,
             width: 20,
            height: 20,
          ),
          Image(
             image: AssetImage(yyyyy),
             fit: BoxFit.fill,
             width: 20,
            height: 20,
          ),
      ],
    );
    
    第 2 条附言  ·  353 天前

    方法1:

     Row(
      children: ['aa', 'bb'].map(
             (e) => Image(
                   image: AssetImage(e),
                   fit: BoxFit.fill,
                   width: 20,
                   height: 20,
                   ),
             ).toList(),
    );
    

    或者

     Row(
      children:[
        _getImage('xxxxx'),
        _getImage('yyyyy'),
       ],
    );  
    
    Widget _getImage(String asset){
      return Image(
             image: AssetImage(asset),
             fit: BoxFit.fill,
             width: 20,
             height: 20,
          );
    }
    

    方法2:

    const Row(
      children: [
         Image(
             image: AssetImage(xxxxx),
             fit: BoxFit.fill,
             width: 20,
            height: 20,
          ),
          Image(
             image: AssetImage(yyyyy),
             fit: BoxFit.fill,
             width: 20,
            height: 20,
          ),
      ],
    );
    

    这个才是,刚复制时忘记删除const了

    17 条回复    2023-12-06 12:35:44 +08:00
    w19961009
        1
    w19961009  
       353 天前
    提炼方法变成提炼成 widget ,新 widget 在构造方法 const 修饰
    purringpal
        2
    purringpal  
       353 天前 via iPhone
    按我的理解,你在 return 的时候加 const ,不就一样了,而且你 IDE 不会提示的吗
    zqlcrow
        3
    zqlcrow  
    OP
       353 天前
    @purringpal
    参数都是动态传入,怎么能加 const 呢。

    比如
    Image(
    image: AssetImage(imageUrl),
    fit: BoxFit.fill,
    width:20,
    height: 20,
    ),

    imageUrl 是动态传入的,那么这个 Image 就不能是 const 的。
    zqlcrow
        4
    zqlcrow  
    OP
       353 天前
    @w19961009
    可行。

    但没搞清楚,const 除了在 rebuild 时能带来性能差异之外,在首次 build 时,也有差异吗?
    AoEiuV020JP
        5
    AoEiuV020JP  
       353 天前
    我有些不理解的是明明 flutter 那个 dart fix 可以自动把整个页面所有能上 const 的控件全都上齐了,那为什么还要人写?编译运行时自动补上不就好了,
    类似 jdk 8 可以省略传入匿名内部类变量的 final 修饰,既然编译器能知道这里要加 final ,那就干脆自动加上省得写了,

    另外楼主的问题,1 确实不是 flutter 推荐做法,封装成方法后参数是变量,这里用变量初始化的控件是“不能”加 const 的,而方法调用这里哪怕传入的是常量,flutter 也是“不支持”给方法调用加 const 的,结果就是封装成方法就无法使用 const ,所以 ide 不会提示加,@purringpal
    zqlcrow
        6
    zqlcrow  
    OP
       353 天前
    @AoEiuV020JP 可是 2 的写法,未免太弱智了。
    AoEiuV020JP
        7
    AoEiuV020JP  
       353 天前
    @zqlcrow #4 首次 build 就看有没有完全相同的控件了,按你说的一个页面 4 个一样的控件,用 const 那最终就能复用,少初始化几个控件,性能更好是自然的,
    AoEiuV020JP
        8
    AoEiuV020JP  
       353 天前
    @zqlcrow #6 推荐做法就是一楼的方案,没有其他的选择了,
    2 是任何编程语言都不推荐的写法,和 flutter 无关,
    zqlcrow
        9
    zqlcrow  
    OP
       353 天前
    @AoEiuV020JP 口误。
    应该是 4 个,相似的元素。
    比如只有 image 和 text 不同。
    AoEiuV020JP
        10
    AoEiuV020JP  
       353 天前
    @zqlcrow #9 这个情况,理论上不涉及复用的话 const 没有什么好处,首次 build 创建四个 const 控件和创建四个普通控件应当是没什么区别的,
    purringpal
        11
    purringpal  
       353 天前
    @zqlcrow 了解了。
    不过我的角度是 const 本身,如果一个对象是可以在编译时确定的,那无论你封装多少层,它应该依然可以在编译时确定,反之亦然。

    所以如果你的传参是常量,那就不要传参,在函数里直接赋值,如果传参不是常量,那又何来 const 。可解?
    AoEiuV020JP
        12
    AoEiuV020JP  
       353 天前
    @zqlcrow #9 不过考虑现实,实际用户首次加载一个页面也可能因为加载设置和异步数据之类的原因多次刷新,这时候 const 好处就体现出来了,这部分可以避免重复初始化,哪怕在用户看来这个页面明明只是第一次加载,
    tool2d
        13
    tool2d  
       353 天前
    看性能需求吧。

    处理业务的时候,我大部分时候都不加 const ,代码运行慢点就慢点。

    但是我看老外和大公司代码,基本上都是加 const 的。
    zqlcrow
        14
    zqlcrow  
    OP
       353 天前
    @AoEiuV020JP 补充了下 1 和 2 的例子
    AoEiuV020JP
        15
    AoEiuV020JP  
       353 天前
    @purringpal #11 主要还是“不支持”,你说这个理论上是可以的,但可能是分析难度的考虑,flutter”不支持“对方法调用指定 const ,
    也就是你有,
    Text('1')
    Text('2')
    Text('3')
    Text('4')
    四个控件这样写就都可以是 const ,
    但如果你封闭成,
    Widget create(String t) {
    return Text(t);
    }
    然后调用,
    create('1')
    create('2')
    create('3')
    create('4')
    这时候两边都是不能 const 的,内部因为这个 t 是”变量“,所以 Text 不能设置 const ,
    外部因为方法调用”不支持“设置 const ,毕竟不好分析你这方法内部有没有使用什么参数以外的其他变量,
    AoEiuV020JP
        16
    AoEiuV020JP  
       353 天前
    @zqlcrow #14 用 map 这个确实纠结了,但封装成 widget 依然是 flutter 上唯一正确的解,哪怕觉得可能不如 map 简洁直观,但也不差,
    const Row(
    children: [
    ImageA(xxxxx),
    ImageA(yyyyy),
    ],
    );
    purringpal
        17
    purringpal  
       353 天前
    @AoEiuV020JP 明白了,👍
    既然是唯一解,如果有个插件能一键封装,可能就最优解了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2807 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 07:46 · PVG 15:46 · LAX 23:46 · JFK 02:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.