這是我參與更文挑戰的第12天,活動詳情查看: 更文挑戰html
前面幾篇介紹了ListView
、GridView
、Wrap
、Column
、Row
等這些在平面列表佈局,今天咱們要聊的是 Stack
,能夠叫他棧佈局
也叫層級佈局
,主要來顯示平面重疊佈局,能夠更加靈活的控制子項的位置。git
這裏咱們添加 3 個大小不一樣子項,看看他們是怎麼排列的。github
Stack(
children: [
getItem(3, width: 120, height: 120, color: Colors.purple),
getItem(2, width: 80, height: 80, color: Colors.blue),
getItem(1),
],
)
複製代碼
這裏除 index 外,其餘參數使用了選擇參數api
/// 獲取子項目(這裏使用了選擇參數)
Widget getItem(int index,
{double? width = 60, double? height = 60, Color color = Colors.orange}) {
return Container(
// 寬高設置 60
width: width,
height: height,
// 設置背景色
color: color,
// 設置間隙
margin: EdgeInsets.all(2),
// 設置子項居中
alignment: Alignment.center,
// 設置子項
child: Text('$index'),
);
}
複製代碼
若是你看看源碼能夠看到這個參數的默認值是 AlignmentDirectional.topStart
,可是這裏咱們依然可使用咱們熟悉的 Alignment.topLeft
來進行參數設置,這是爲何呢?咱們看看來看看 AlignmentDirectional
源碼吧,Alignment
源碼在前面的章節咱們看過了markdown
Stack(
// 居中對齊
alignment: Alignment.topLeft,
children: [
getItem(3, width: 120, height: 120, color: Colors.purple),
getItem(2, width: 80, height: 80, color: Colors.blue),
getItem(1),
],
)
複製代碼
// Alignment
class Alignment extends AlignmentGeometry {
/// Creates an alignment.
///
/// The [x] and [y] arguments must not be null.
const Alignment(this.x, this.y)
: assert(x != null),
assert(y != null);
static const Alignment topLeft = Alignment(-1.0, -1.0);
static const Alignment center = Alignment(0.0, 0.0);
...
}
// AlignmentDirectional
class AlignmentDirectional extends AlignmentGeometry {
const AlignmentDirectional(this.start, this.y)
: assert(start != null),
assert(y != null);
static const AlignmentDirectional topStart = AlignmentDirectional(-1.0, -1.0);
// 考慮使用 Alignment.center 代替
static const AlignmentDirectional center = AlignmentDirectional(0.0, 0.0);
...
}
複製代碼
上面咱們貼出了核心源碼,能夠看出他倆都是繼承自 AlignmentGeometry
,而後實現也是差很少,並且源碼中的註釋也是推薦咱們使用 Alignment 代替oop
這裏咱們就使用 Alignment 了源碼分析
Alignment.topLeft | Alignment.topCenter | Alignment.topRight |
---|---|---|
Alignment.centerLeft | Alignment.center | Alignment.centerRight |
Alignment.bottomLeft | Alignment.bottomCenter | Alignment.bottomRight |
當咱們輸入 **Alignment.bottomRight**
這類參數時,由於單次比較長若是所有輸入就太麻煩了,咱們能夠輸入部分前綴+常量的首字母,以下佈局
閱讀我得文章你會發現,不光有源碼分析、結構化梳理還有各類實用的技巧,記得關注我哦post
爲了展現效果,咱們先添加一個背景 BgContainer
(以前的篇章封裝的通用組件)ui
BgContainer(
child: Stack(
// 居中
alignment: Alignment.center,
// 設置默認值 loose
fit: StackFit.loose,
children: [
getItem(3, width: 120, height: 120, color: Colors.purple),
getItem(2, width: 80, height: 80, color: Colors.blue),
getItem(1),
],
),
)
複製代碼
這裏爲了顯示效果咱們使用了 DevTools 中的 Widget Inspector
來調試佈局,以後可能會聊 Flutter DevTools 的使用技巧(這裏不作承諾,仍是可能回聊)
經過上圖能夠看到此時 Stack 的大小取決於子項中最大的(也就是紫色 120
寬高的子項)
這裏彷佛不是很符合預期,理論上不該該是擴展 Stack 到最大便可嗎?
目前咱們的子項都是沒有設置定位的,因此此時全部的子類約束都會擴展到與Stack 最大值一致
咱們此時作一點點改變看看效果,先看代碼
BgContainer(
child: Stack(
alignment: Alignment.center,
fit: StackFit.expand,
children: [
getItem(3, width: 120, height: 120, color: Colors.purple),
getItem(2, width: 80, height: 80, color: Colors.blue),
// 這添加了定位
Positioned(
// 距左邊 10
left: 10,
// 距上邊 10
top: 10,
child: getItem(1),
),
],
),
)
複製代碼
此時看到效果了,1 黃色
子項遵循了本身的約束,由於他添加了定位,其餘 二、3
由於沒有添加定位因此和 Stack
同樣大,約束被傳遞。
這裏咱們暫時不講定位的使用,下篇咱們系統的聊
咱們先看看效果
這裏彷佛和 loose
沒有啥區別啊?咱們能夠看看源碼後改變成如下的示例代碼再看看
BgContainer(
// 添加了一個橫向佈局
child: Row(
children: [
// 添加了展開組件,前面講過能夠去專欄看看
Expanded(
child: Stack(
alignment: Alignment.center,
// 設置填充方式爲 passthrough
fit: StackFit.passthrough,
children: [
getItem(3, width: 120, height: 120, color: Colors.purple),
getItem(2, width: 80, height: 80, color: Colors.blue),
Positioned(
left: 10,
top: 10,
child: getItem(1),
),
],
),
)
],
),
),
)
複製代碼
這裏咱們看到與 expand
還有些不一樣,這裏咱們只展開了寬度,高度仍是子項的高度。由於這裏 Stack
的寬度約束是展開的屏幕寬度,直接傳遞給了沒有添加定位的子組件,因此看到 二、3
子組件跟着變了,而 1
子組件的大小沒有發生變化。
對於非定位組件會繼續保持對齊方式和子項的約束
爲啥不聊 overflow
呢,由於本文是基於 Flutter 2.2.1 版本的,overflow
已經被棄用了,不少地方的剪裁行爲之後都統一爲 clipBehavior
,這參數咱們以前在剪裁篇《Flutter 中各類剪裁 Widget 的使用》聊過,建議回看
當咱們設置的子項定位後大小超過了 Stack 佈局的時候,咱們指望怎樣剪裁渲染呢?是剪裁仍是顯示,是帶抗鋸齒仍是不帶呢?
BgContainer(
child: Stack(
alignment: Alignment.center,
fit: StackFit.passthrough,
// 設置剪裁行爲默認 hardEdge
clipBehavior: Clip.hardEdge,
children: [
getItem(3, width: 120, height: 120, color: Colors.purple),
getItem(2, width: 80, height: 80, color: Colors.blue),
// 這裏設置定位左上角 -20
Positioned(
left: -20,
top: -20,
child: getItem(1),
),
],
),
)
複製代碼
Clip.none(不剪裁) | Clip.hardEdge | antiAlias、antiAliasWithSaveLayer |
---|---|---|
通常是默認和不剪裁進行設置,其餘的能夠回看剪裁篇,介紹了不一樣。
到這裏 Stack 核心內容就聊完了,下篇咱們結合聊定位組件「Positioned、Align」聊聊,記得關注個人專欄哦
基於 Flutter 🔥 最新版本
👏 歡迎點贊➕收藏➕關注,有任何問題隨時在下面👇評論,我會第一時間回覆哦