詳細介紹Container的相關使用。
一、簡介
A convenience widget that combines common painting, positioning, and sizing widgets.
一個使用方便的小部件,它融合了常見的繪畫,定位和大小調整。
1、構造函數
Container({
Key key, //
this.alignment, //對齊方式,作用於child,譬如如果是center,表示child在container裏面居中
this.padding, //內部間距
Color color, //背景色,
Decoration decoration, //背景裝飾,與color 不能共存,如需要設置背景,裏面也設置背景的方式。
this.foregroundDecoration, //前景裝飾
double width, //寬度
double height, //高度
BoxConstraints constraints, //容器大小的限制條件,跟寬高的區別是
this.margin, //間距,類似於layoutParams 的maring.
this.transform, //變換,類似於安卓的矩陣變換.
this.child, //對應的控件
});
Container
的使用的場景比較廣泛,其他的控件都可以加多一層進行包裝,以此來實現margin、pading
等相關功能。
看到其構造函數,有一點可能比較疑惑的,不是有寬高了嗎?爲啥還有個constraints?其實這兩個都是指定容器大小,
但如果同時存在,會以constraints
爲準,其實width、height的最後實現,也是通過constraints
來做的。
2、繼承關係
Object (dart.core)
Diagnosticable (diagnostics.dart)
DiagnosticableTree (diagnostics.dart)
Widget (framework.dart)
StatelessWidget (framework.dart)
Container (container.dart)
3、繪製過程
- 最裏層是child
- child外層由Padding包着
- 然後添加額外的constraints限制
- 最後添加margin
繪製的時候,首先繪製給定的變換(transform),然後繪製裝飾填充物,接着繪製child,最後將前景裝飾繪製出來。
Container Widget 在沒有子child的情況下,會儘可能地變大,除非傳入的constraints是無邊界的,在這種情況下,container會儘可能地小。
在有child的情況下,會根據child的參數來決定,但如果container 設置了width 、height或者constraints,則會根據這些參數來繪製。
4、佈局實現
因爲Container融合了其他的一些widget,並且這些widget都有各自的佈局行爲,所以Container的佈局方式有一些複雜。
總的來說:容器會嘗試以下操作:
- 遵守對齊方式,根據子項調整大小,
- 遵守寬度,高度和約束,
- 擴展以適配父親,以使其儘可能小
具體來講就是:
如果container
沒有孩子,沒有設置寬高,沒有設置constraints
,並且父容器設置了constraints
爲 unbounded
,那麼container
會讓自己儘可能的小;
如果container
沒有孩子並且沒有設置對齊方式,但是設置了寬高或者constraints
(寬度最後其實都會轉換成constraints
去佈局),他會根據自己的constraints
和父節點的constraints
,儘可能地小;
如果container
沒有孩子,沒有寬高沒有constraints
和alignment
,但是父節點設置了有界的約束,那麼container
會儘可能根據父節點的有界約束儘可能地撐大自己;
如果container
設置了對齊方式,並且父節點設置了無邊界的約束,那麼container
會調節自身尺寸來包住子child
;
如果container
設置了對齊方式,並且父節點設置了有邊界的約束,那麼container
會儘可能地撐大自己(根據父節點的大小),然後將其子child按照設置的alignment
進行調整;
如果container
只有子child
,沒有設置寬高,沒有設置constraints
,沒有設置alignment,那麼container
就會將父節點的constraints
傳遞給孩子,並根據child進行調整;
二、使用方式
1、代碼示例
class ContainerWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 200,
height: 200,
alignment: Alignment.center,
margin: EdgeInsets.only(top: 45, left: 120),
padding: EdgeInsets.all(20),
// color: Colors.yellow,
decoration: BoxDecoration( //背景裝飾
color: Colors.yellow,
gradient: RadialGradient( //漸變
colors: [Colors.red, Colors.orange],
center: Alignment.center,
radius: .98,
),
boxShadow: [ //卡片陰影
BoxShadow(
color: Colors.black54,
offset: Offset(2.0, 2.0),
blurRadius: 4.0
)
]
),
transform: Matrix4.rotationZ(0.2),
child: Text("520", style: TextStyle(color: Colors.white, fontSize: 40.0), ),
);
}
}
2、效果圖
這裏面的padding 和maring,如果你做過安卓或者iOS的開發,應該比較容易理解,其實就是一個是內部的空白,一個是外部的空白。
3、適用場景
- 需要設置背景色;
- 需要設置圓角;
- 需要設置背景圖片;
- 需要設置間距;
三、源碼解析
@override
Widget build(BuildContext context) {
Widget current = child;
//如果沒有child,並且沒有設置constraints,那麼就創建一個LimitedBox,
if (child == null && (constraints == null || !constraints.isTight)) {
current = LimitedBox(
maxWidth: 0.0,
maxHeight: 0.0,
child: ConstrainedBox(constraints: const BoxConstraints.expand()),
);
}
//設置對齊方式
if (alignment != null)
current = Align(alignment: alignment, child: current);
final EdgeInsetsGeometry effectivePadding = _paddingIncludingDecoration;
//設置間距
if (effectivePadding != null)
current = Padding(padding: effectivePadding, child: current);
//設置背景色
if (decoration != null)
current = DecoratedBox(decoration: decoration, child: current);
//設置前景色
if (foregroundDecoration != null) {
current = DecoratedBox(
decoration: foregroundDecoration,
position: DecorationPosition.foreground,
child: current,
);
}
//設置約束
if (constraints != null)
current = ConstrainedBox(constraints: constraints, child: current);
//設置margin,其實最終也是包了一層padding來實現;
if (margin != null)
current = Padding(padding: margin, child: current);
//最後,設置變換Transform
if (transform != null)
current = Transform(transform: transform, child: current);
return current;
}
build
方法其實並不複雜,每行做的事情,已經註釋,總的來講,就是不設置約束情況,按照父節點儘可能大,如果有約束,則按照內部的來。
四、參考
https://api.flutter.dev/flutter/widgets/Container-class.html