簡介
A convenience widget that combines common painting, positioning, and sizing widgets.
Container 在Flutter中非常常見, 是一個結(jié)合繪制(painting), 定位(position)以及尺寸(sizing)的widget.
組成
Container的組成如下:
- 最里層的是child元素;
- child元素首先會被padding包著;
- 然后添加額外的constraints限制;
- 最后添加margin.
Container的繪制的過程如下:
- 首先會繪制transform效果;
- 接著繪制decoration;
- 后繪制child;
- 最后繪制foregroundDecoration.
Container自身尺寸的調(diào)節(jié)分兩種情況:
- Container在沒有子節(jié)點(children)的時候,會試圖去變得足夠大。除非constraints是unbounded限制走诞,在這種情況下会油,Container會試圖去變得足夠小。
- 帶子節(jié)點的Container贾费,會根據(jù)子節(jié)點尺寸調(diào)節(jié)自身尺寸钦购,但是Container構(gòu)造器中如果包含了width、height以及constraints褂萧,則會按照構(gòu)造器中的參數(shù)來進行尺寸的調(diào)節(jié)押桃。
源碼解析
構(gòu)造函數(shù)如下:
Container({
Key key,
this.alignment,
this.padding,
Color color,
Decoration decoration,
this.foregroundDecoration,
double width,
double height,
BoxConstraints constraints,
this.margin,
this.transform,
this.child,
})
屬性解析
key:Container唯一標識符,用于查找更新导犹。
alignment:控制child的對齊方式虎眨,如果container或者container父節(jié)點尺寸大于child的尺寸弯淘,這個屬性設(shè)置會起作用,有很多種對齊方式。
padding:decoration內(nèi)部的空白區(qū)域譬重,如果有child的話,child位于padding內(nèi)部尝抖。padding與margin的不同之處在于伴嗡,padding是包含在content內(nèi),而margin則是外部邊界,設(shè)置點擊事件的話纫骑,padding區(qū)域會響應(yīng)蝎亚,而margin區(qū)域不會響應(yīng)。
color:用來設(shè)置container背景色先馆,如果foregroundDecoration設(shè)置的話发框,可能會遮蓋color效果。
decoration:繪制在child后面的裝飾煤墙,設(shè)置了decoration的話梅惯,就不能設(shè)置color屬性,否則會報錯仿野,此時應(yīng)該在decoration中進行顏色的設(shè)置铣减。
foregroundDecoration:繪制在child前面的裝飾。
width:container的寬度脚作,設(shè)置為double.infinity可以強制在寬度上撐滿葫哗,不設(shè)置,則根據(jù)child和父節(jié)點兩者一起布局球涛。
height:container的高度劣针,設(shè)置為double.infinity可以強制在高度上撐滿。
constraints:添加到child上額外的約束條件亿扁。
margin:圍繞在decoration和child之外的空白區(qū)域捺典,不屬于內(nèi)容區(qū)域。
transform:設(shè)置container的變換矩陣从祝,類型為Matrix4襟己。
child:container中的內(nèi)容widget。
源碼
decoration = decoration ?? (color != null ? new BoxDecoration(color: color) : null),
可以看出, 對于顏色的設(shè)置哄褒,最后都是轉(zhuǎn)換為decoration來進行繪制的稀蟋。如果同時包含decoration和color兩種屬性,則會報錯呐赡。
@override
Widget build(BuildContext context) {
Widget current = child;
if (child == null && (constraints == null || !constraints.isTight)) {
current = new LimitedBox(
maxWidth: 0.0,
maxHeight: 0.0,
child: new ConstrainedBox(constraints: const BoxConstraints.expand())
);
}
if (alignment != null)
current = new Align(alignment: alignment, child: current);
final EdgeInsetsGeometry effectivePadding = _paddingIncludingDecoration;
if (effectivePadding != null)
current = new Padding(padding: effectivePadding, child: current);
if (decoration != null)
current = new DecoratedBox(decoration: decoration, child: current);
if (foregroundDecoration != null) {
current = new DecoratedBox(
decoration: foregroundDecoration,
position: DecorationPosition.foreground,
child: current
);
}
if (constraints != null)
current = new ConstrainedBox(constraints: constraints, child: current);
if (margin != null)
current = new Padding(padding: margin, child: current);
if (transform != null)
current = new Transform(transform: transform, child: current);
return current;
}
Container 的 build 函數(shù)的繪制過程是一個線形的判斷過程, 一層層的包裹著Widget, 去實現(xiàn)不同的樣式.
示例
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePage createState() => _MyHomePage();
}
class _MyHomePage extends State<MyHomePage> {
String textToShow = "I like Flutter";
void _updateText(){
print('點擊');
setState(() {
textToShow = "Flutter is Awesome";
});
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new SamplePage())
);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Sample App")
),
body: new Container(
constraints: new BoxConstraints.expand(
height: Theme.of(context).textTheme.display1.fontSize * 1.1 + 200
),
decoration: new BoxDecoration(
border: new Border.all(width: 2.0, color: Colors.red),
color: Colors.grey,
borderRadius: new BorderRadius.all(new Radius.circular(20)),
image: new DecorationImage(
image: new NetworkImage('http://h.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=0d023672312ac65c67506e77cec29e27/9f2f070828381f30dea167bbad014c086e06f06c.jpg'),
centerSlice: new Rect.fromLTRB(270, 180, 1360, 730)
),
),
padding: const EdgeInsets.all(8.0),
alignment: Alignment.center,
child: new Text(textToShow,
style: Theme.of(context).textTheme.display1.copyWith(color: Colors.black),
),
transform: new Matrix4.rotationZ(0.3),
),
floatingActionButton: FloatingActionButton(
onPressed: _updateText,
tooltip: 'Update Text',
child: Icon(Icons.update),
),
);
}
}
使用場景
- 需要設(shè)置間隔
- 需要設(shè)置背景
- 需要設(shè)置圓角或者邊框
- 需要對齊
- 需要設(shè)置背景圖片