【Flutter 元件集錄】Stack | 8 月更文挑戰

張風捷特烈發表於2021-08-23
前言:

這是我參與8月更文挑戰的第 23 天,活動詳情檢視:8月更文挑戰。為應掘金的八月更文挑戰,我準備在本月挑選 31 個以前沒有介紹過的元件,進行全面分析和屬性介紹。這些文章將來會作為 Flutter 元件集錄 的重要素材。希望可以堅持下去,你的支援將是我最大的動力~

本系列元件文章列表
1.NotificationListener2.Dismissible3.Switch
4.Scrollbar5.ClipPath6.CupertinoActivityIndicator
7.Opacity8.FadeTransition9. AnimatedOpacity
10. FadeInImage11. Offstage12. TickerMode
13. Visibility14. Padding15. AnimatedContainer
16.CircleAvatar17.PhysicalShape18.Divider
19.Flexible、Expanded 和 Spacer 20.Card21.SizedBox
22.ConstrainedBox23.Stack

1. 認識 Stack 元件

Stack 是一個經常被用到的元件,我看可以通過它來疊合若干個元件。原始碼中對它的介紹是:

一個將其子部件,相對於盒邊緣進行定位的元件。
複製程式碼

也就是說 Stack 元件擅長的是 定位 元件。下面是 Stack 元件類的定義構造方法,可以看出它繼承自 MultiChildRenderObjectWidget。所以可接受一個元件列表。另外還有一些配置引數,在下面將一一介紹 。


2. Stack 元件的簡單使用

如下,通過 Stack 將藍色盒子、紅色盒子和一個圖示疊放在一起。可以看出,預設情況下元件會以 Stack 區域的左上角進行對齊疊放,且會根據列表元素的順序依次疊放。

Stack(
  children: <Widget>[
    Container( width: 100, height: 100, color: Colors.red ),
    Container( width: 60, height: 60, color: Colors.green ),
    Icon(Icons.ac_unit,color: Colors.white )
  ],
);
複製程式碼

textDirection屬性

根據不同國家的閱讀習慣,給出 textDirection 來確定排布方向。其型別為 TextDirection 列舉,有兩個元素,rtl 代表從右向左,ltr 代表從左向右,我們的閱讀習慣自然是 ltr

enum TextDirection {
  /// The text flows from right to left (e.g. Arabic, Hebrew).
  rtl,
  /// The text flows from left to right (e.g., English, French).
  ltr,
}
複製程式碼

當把 textDirection 設為 rtl 時,效果如下,會以 Stack 區域的右上角進行對齊疊放。

Stack(
  textDirection: TextDirection.rtl,
  children: <Widget>[
    Container( width: 100, height: 100, color: Colors.red ),
    Container( width: 60, height: 60, color: Colors.green ),
    Icon(Icons.ac_unit,color: Colors.white )
  ],
);
複製程式碼

alignment屬性

alignment 屬性我們應該非常熟悉,它的型別是 AlignmentGeometry ,用於控制對齊方式。比如將 alignment 設定為 Alignment.center 常量,就會在 Stack 中居中排布。

Stack(
  alignment: Alignment.center,
  children: <Widget>[
    Container( width: 100, height: 100, color: Colors.red ),
    Container( width: 60, height: 60, color: Colors.green ),
    Icon(Icons.ac_unit,color: Colors.white )
  ],
);
複製程式碼

另外 Alignment 除了八個方位外,可以自己指定對齊方式。之前再 《出神入化的Align》 一文中詳細介紹了 alignment 屬性的用法,這裡不再贅述。比如下面是 Alignment(0.2,0.2) 的效果。


3. Stack 的 fit 屬性

fit 屬性型別為 StackFit 列舉,有如下三個元素。預設情況下是 loose

enum StackFit {
  loose,
  expand,
  passthrough,
}
複製程式碼

先看個例子:如下,在 Stack 外層通過 ConstrainedBox 施加一個寬高固定的約束,毫無疑問 Stack 在被強制約束後,其佔位區域被固定。

ConstrainedBox(
  constraints: BoxConstraints.tightFor(width:200,height:150),
  child: Stack(
  fit: StackFit.loose,
  children: <Widget>[
    Container(width: 100, height: 100, color: Colors.red),
    Container(width: 60, height: 60, color: Colors.green),
    Icon(Icons.ac_unit,color: Colors.white,)
  ],
));
複製程式碼

可以看出,在 StackFit.loose 的情況下,子元件並未受到該固定尺寸的約束,而是以該固定區域為上限的鬆散約束,如下紅色所示。


此時,在 StackFit.expand 的情況下,子元件也會受到一個固定尺寸的強約束。

Container 在該約束下,會變成固定的寬高,即使藍色自身要求是 60*60

其實稍微瞄一下 RenderStack 的原始碼我們就能知道 fit 具體的處理邏輯。在 loose 時,會通過 constraints.loosen() 將建立一個鬆散約束,該方法就是將最小寬高設為 0 ,最大寬高設為對應最大值。而 expand 會將自身約束的最大區域最為固定寬高約束。最後 passthrough 則什麼都不處理,直接將自身約束施加給子節點。

BoxConstraints loosen() {
  assert(debugAssertIsValid());
  return BoxConstraints(
    minWidth: 0.0,
    maxWidth: maxWidth,
    minHeight: 0.0,
    maxHeight: maxHeight,
  );
}
複製程式碼

4. Stack 的 overflow 與 clipBehavior 屬性

我們可以清楚地看到 overflow 屬性是一個過時的屬性,而 clipBehavior 就是替代它的。clipBehavior 是什麼我就不多說了,詳見 ClipPath 一文。

那為什麼需要 clipBehavior 進行裁剪呢?通過 Positioned 元件可以對子元件進行精確定位,甚至是負數。如下左邊偏移 -20 ,右邊偏移 -10 。預設裁剪行為是 hardEdge ,效果如下:

class StackDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return
      Container(
        color: Colors.grey.withAlpha(33),
        constraints: BoxConstraints.tightFor(width:200,height:150),
        child: Stack(
        children: <Widget>[
          Container(width: 100, height: 100, color: Colors.red),
          Positioned(
              left: -20,
              top: -10,
              child: Container(width: 60, height: 60, color: Colors.green)),
          Icon(Icons.ac_unit,color: Colors.white,)
        ],
      ));
  }
}
複製程式碼

clipBehavior: Clip.none, 時,不會進行裁剪,出界的就會被顯示出來。注意一點,出界的部分是無法響應點選事件的。如果需要點選,有其他元件能夠解決。


Stack 的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~

相關文章