Flutter即學即用系列博客—07 RenderFlex overflowed 引發的思考

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')
],
);
/<widget>

模擬器效果如下:

Flutter即學即用系列博客—07 RenderFlex overflowed 引發的思考

思考

其實一般遇到這種情況,都應該考慮一下是否這樣佈局合理。

上面這個我們只是舉個例子,因為一般如果只有一張圖片,是不需要給他套一層 Row 的。

因為情況比較多,這裡假設有時候真的就需要這麼處理,怎麼辦?

解決方法

如果你某個 Widget 出現了上面的問題,而且真的不是佈局問題,而是真的就是有可能出現這種情況,但是你不希望 debug 模式顯示這個錯誤,那麼可以給他套一層 Expanded。

官網有如下說明:

A widget that expands a child of a Row, Column, or Flex.

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'),,
)
],
);
/<widget>

效果如下:

Flutter即學即用系列博客—07 RenderFlex overflowed 引發的思考

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,
),
),
],
);
/<widget>

效果圖如下:

Flutter即學即用系列博客—07 RenderFlex overflowed 引發的思考

可以看出 Expanded 的 flex 屬性會按比例佈局。

Sample

我們來實現一個簡單的 UI。

如下圖,可以看到是一個網絡錯誤時,點擊重試的頁面。

Flutter即學即用系列博客—07 RenderFlex overflowed 引發的思考

假設你之前習慣了 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
),
)
)
],

),
);
}
}
/<widget>

效果如下:

Flutter即學即用系列博客—07 RenderFlex overflowed 引發的思考

你會發現這種實現方式的適配性會很差,而且可能出現上面的問題。

因此我們看下使用 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(),
),
],
),
);
}
}
/<widget>

效果如下:

Flutter即學即用系列博客—07 RenderFlex overflowed 引發的思考

其實,看到上面用到的 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),
)),
],

),
);
}
}
/<widget>

效果如下:

Flutter即學即用系列博客—07 RenderFlex overflowed 引發的思考

其中實現方式一隻是說明,實際開發不推薦。

實現方式二和實現方式三都可以,推薦方式三。

相關代碼及 sketch 圖都放到了 GitHub 倉庫:

https://github.com/nesger/FlutterSample

其中分支 feature/ui-refresh-one 是實現方式一。

分支 feature/ui-refresh-two 是實現方式二。

分支 feature/ui-refresh-three 是實現方式三。

這裡按鈕寬度和高度沒有指定,大家可以根據情況確定是否指定哈~

總之就是:

實現方式千萬條,合適第一條。

適配不精確,測試兩行淚。

更多閱讀:


分享到:


相關文章: