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 仓库
Flutter 即学即用系列博客——07 RenderFlex overflowed 引发的思考的更多相关文章
- Flutter 即学即用系列博客——09 EventChannel 实现原生与 Flutter 通信(一)
前言 紧接着上一篇,这一篇我们讲一下原生怎么给 Flutter 发信号,即原生-> Flutter 还是通过 Flutter 官网的 Example 来讲解. 案例 接着上一次,这一次我们让原生 ...
- Flutter 即学即用系列博客——08 MethodChannel 实现 Flutter 与原生通信
背景 前面我们讲了很多 Flutter 相关的知识点,但是我们并没有介绍怎样实现 Flutter 与原生的通信. 比如我在 Flutter UI 上面点击了一个按钮,我希望原生做一些处理,那么原生怎么 ...
- Flutter 即学即用系列博客总结篇
前言 迟到的总结篇,其实大家看我之前发的系列博客最后一篇,发文时间是 3 月 29 日.距离现在快两个月了. 主要是因为有很多事情在忙,所以这篇就耽搁了. 今天终于可以跟大家会面了. 系列博客背景 F ...
- Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget
前言 上一篇我们对 Flutter UI 有了一个基本的了解. 这一篇我们通过自定义 Widget 来了解下如何写一个 Widget? 然而 Widget 有两个,StatelessWidget 和 ...
- Flutter 即学即用系列博客——04 Flutter UI 初窥
前面三篇可以算是一个小小的里程碑. 主要是介绍了 Flutter 环境的搭建.如何创建 Flutter 项目以及如何在旧有 Android 项目引入 Flutter. 这一篇我们来学习下 Flutte ...
- Flutter 即学即用系列博客——09 MethodChannel 实现原生与 Flutter 通信(二)
前言 上一篇我们讲解了如何通过 EventChannel 实现 Android -> Flutter 的通信. 并且也看到了 Flutter 内部 EventChannel 源码也是对 Meth ...
- Flutter 即学即用系列博客——06 超实用 Widget 集锦
本篇文章我们来讲讲一些比较常用的 Widget. 大家验证的时候使用下面的代码替换 main.dart 代码,然后在 //TODO 语句返回下面常用 Widget 示例的代码. import 'pac ...
- Flutter 即学即用系列博客——03 在旧有项目引入 Flutter
前言 其实如果打算在实际项目中引入 Flutter,完全将旧有项目改造成纯 Flutter 项目的可能性比较小,更多的是在旧有项目引入 Flutter. 因此本篇我们就说一说如何在旧有项目引入 Flu ...
- Flutter 即学即用系列博客——10 混淆
前言 之前的博客我们都是在 debug 的模式下进行开发的. 实际发布到市场或者给到用户的都是 release 包. 而对于 Android 来说,release 包一个重要的步骤就是混淆. Andr ...
随机推荐
- Spring Cloud Config 分布式配置中心使用教程
一.简介 在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件.在Spring Cloud中,有分布式配置中心组件spring cloud config ...
- PAT1021:Deepest Root
1021. Deepest Root (25) 时间限制 1500 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A graph ...
- Oracle 服务启动关闭
有没有感觉到,自从装上Oracle之后,电脑变卡了?卡是正常的,oracle作为大型数据库软件,运行起来是非常吃内存的. 所以对于自用的电脑来说,不使用Oracle的时候,应该把Oracle的一系列服 ...
- iPhone越狱
手机越狱 常用工具:PP越狱助手.盘古越狱.iTunes 如果手机第一次越狱使用pp越狱助手成功率比较高 iPhone固件下载地址http://iphone.91.com/fw/iphone5/ 具体 ...
- Java的锁
今天练习了Java的多线程,提到多线程就基本就会用到锁 Java通过关键字及几个类实现了锁的机制,这里先介绍下Java都有哪些锁: 一.Java实现锁的机制: Java运行到包含锁的代码时,获取尝 ...
- Linux时间子系统之二:Alarm Timer
一.前言 严格来讲Alarm Timer也算POSIX Timer一部分,包含两种类型CLOCK_REALTIME_ALARM和CLOCK_BOOTTIME_ALARM.分别是在CLOCK_REALT ...
- aliyun TableStore相关操作汇总
总结:这个东西本身可能技术还不成熟,使用的人少,有问题很验证解决 遇到的问题:(1)没有一个GUI工具,使用门槛高(2)查询的GetRange不方便,把查询出来的数据使用System.out.prin ...
- 微机原理基础(四)—— MSC51
一.MCS51基本组成(STC89C52) CPU(8051CPU) + 存储器(4KB ROM/256B RAM)+外设(4组IO口,两个定时器,一个串口) 1.组成结构简图 ...
- app后端设计(2)--xmpp的使用(2014.01.14更新)
在app中有时候是需要添加聊天服务,在这里谈谈曾经开发聊天服务的经验: (1)聊天服务端选的openfire,这是一个基于xmpp协议的聊天服务器(XMPP是一种基于XML的协议,它继承了在XML环境 ...
- JS 总结
加var与不加var的区别: 简单来说就是加了var是局部变量 不加是全局变量.只有加了var的情况下就能限定该变量的使用范围 这样在别的方法里面也可以命名同样的变量了