Flutter 即学即用系列博客——07 RenderFlex overflowed 引发的思考
背景
在进行 flutter ui 开发的时候,控制台报出了下面错误:
flutter: ══╡ exception caught by rendering library >╞═════════════════════════════════════════════════════════
flutter: the following message was thrown during layout:
flutter: a renderflex overflowed by 826 pixels on the right.
界面的体现就是黄色区域。
这里的代码是在上一篇的基础上返回下面的 widget:
return row( children: <widget>[ image.network( 'https://upload-images.jianshu.io/upload_images/5361063-cfad13c672a06084.jpg?imagemogr2/auto-orient/strip%7cimageview2/2/w/1240') ], );
模拟器效果如下:
思考
其实一般遇到这种情况,都应该考虑一下是否这样布局合理。
上面这个我们只是举个例子,因为一般如果只有一张图片,是不需要给他套一层 row 的。
因为情况比较多,这里假设有时候真的就需要这么处理,怎么办?
解决方法
如果你某个 widget 出现了上面的问题,而且真的不是布局问题,而是真的就是有可能出现这种情况,但是你不希望 debug 模式显示这个错误,那么可以给他套一层 expanded。
官网有如下说明:
using an expanded widget makes a child of a row, column, or flex expand to fill the available space in the main axis (e.g., horizontally for a row or vertically for a column). if multiple children are expanded, the available space is divided among them according to the flex factor.
所以对于 row、column 以及 flex 都可以用 expanded 来解决子组件报上面错误问题。
所以这里可以修改为
return row( children: <widget>[ expanded( child: image.network( 'https://upload-images.jianshu.io/upload_images/5361063-cfad13c672a06084.jpg?imagemogr2/auto-orient/strip%7cimageview2/2/w/1240'),, ) ], );
效果如下:
expanded 妙用
expanded 除了可以解决上面的问题之外,还有一个妙用就是比例布局。
什么意思呢?
我们写下代码,然后给下效果图你就懂了。
return column( children: <widget>[ expanded( flex: 1, child: container( color: colors.red, ), ), expanded( flex: 1, child: container( color: colors.blue, ), ), expanded( flex: 1, child: container( color: colors.grey, ), ), ], );
效果图如下:
可以看出 expanded 的 flex 属性会按比例布局。
sample
我们来实现一个简单的 ui。
如下图,可以看到是一个网络错误时,点击重试的页面。
假设你之前习惯了 sketch 边距开发,你看到这个页面,就直接根据边距进行开发,写出了下面的代码。
实现方式一:
import 'package:flutter/material.dart'; void main() => runapp(myapp()); class myapp extends statelesswidget { @override widget build(buildcontext context) { return materialapp( home: scaffold( backgroundcolor: color(0xfff0f1f0), body: center( child: _buildwidget(), ), ), ); } widget _buildwidget() { return container( child: column( children: <widget>[ padding( padding: const edgeinsets.only(left: 97.0, right: 97.0, top: 125), child: image.asset('assets/images/refresh.png', width: 49, height: 44,), ), sizedbox( height: 42.0, ), flatbutton( padding: const edgeinsets.symmetric(horizontal: 50.0), //注意这里 alpha 最大值是 255, sketch 上面最大值是 100 color: color.fromargb(255, 13, 46, 172), //这里 onpressed 不能为 null,如果写 null 会怎样,大家可以试下~ onpressed: (){}, child: text( //演示而已,实际开发需要多语言 '刷新', style: textstyle( color: colors.white, fontsize: 12, fontweight: fontweight.w600 ), ) ) ], ), ); } }
效果如下:
你会发现这种实现方式的适配性会很差,而且可能出现上面的问题。
因此我们看下使用 expanded 如何实现。
观察一下,我们发现界面大概可以分成 3 块。
每一块占的比例差不多,因此可以如下实现。
实现方式二:
import 'package:flutter/material.dart'; void main() => runapp(myapp()); class myapp extends statelesswidget { @override widget build(buildcontext context) { return materialapp( home: scaffold( backgroundcolor: color(0xfff0f1f0), body: center( child: _buildwidget(), ), ), ); } widget _buildwidget() { return container( child: column( children: <widget>[ expanded( flex: 1, child: container(), ), image.asset('assets/images/refresh.png', width: 49, height: 44,), sizedbox( height: 42.0, ), flatbutton( padding: const edgeinsets.symmetric(horizontal: 50.0), //注意这里 alpha 最大值是 255, sketch 上面最大值是 100 color: color.fromargb(255, 13, 46, 172), //这里 onpressed 不能为 null,如果写 null 会怎样,大家可以试下~ onpressed: (){}, child: text( //演示而已,实际开发需要多语言 '刷新', style: textstyle( color: colors.white, fontsize: 12, fontweight: fontweight.w600 ), ) ), expanded( flex: 1, child: container(), ), ], ), ); } }
效果如下:
其实,看到上面用到的 column,我们可以直接利用上次说到的一个属性,就可以很巧妙的实现适配。
实现方式三:
import 'package:flutter/material.dart'; void main() => runapp(myapp()); class myapp extends statelesswidget { @override widget build(buildcontext context) { return materialapp( home: scaffold( backgroundcolor: color(0xfff0f1f0), body: center( child: _buildwidget(), ), ), ); } widget _buildwidget() { return container( child: column( mainaxisalignment: mainaxisalignment.center, children: <widget>[ image.asset( 'assets/images/refresh.png', width: 49, height: 44, ), sizedbox( height: 42.0, ), flatbutton( padding: const edgeinsets.symmetric(horizontal: 50.0), //注意这里 alpha 最大值是 255, sketch 上面最大值是 100 color: color.fromargb(255, 13, 46, 172), //这里 onpressed 不能为 null,如果写 null 会怎样,大家可以试下~ onpressed: () {}, child: text( //演示而已,实际开发需要多语言 '刷新', style: textstyle( color: colors.white, fontsize: 12, fontweight: fontweight.w600), )), ], ), ); } }
效果如下:
其中实现方式一只是说明,实际开发不推荐。
实现方式二和实现方式三都可以,推荐方式三。
相关代码及 sketch 图都放到了 github 仓库