本文主要介紹Flutter佈局中的LimitedBox、Offstage、OverflowBox、SizedBox四種控件,詳細介紹了其佈局行爲以及使用場景,並對源碼進行了分析。html
A box that limits its size only when it's unconstrained.git
LimitedBox,經過字面意思,也能夠猜想出這個控件的做用,是限制類型的控件。這種類型的控件前面也介紹了很多了,這個是對最大寬高進行限制的控件。github
LimitedBox是將child限制在其設定的最大寬高中的,可是這個限定是有條件的。當LimitedBox最大寬度不受限制時,child的寬度就會受到這個最大寬度的限制,同理高度。bash
Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > LimitedBox
複製代碼
Row(
children: <Widget>[
Container(
color: Colors.red,
width: 100.0,
),
LimitedBox(
maxWidth: 150.0,
child: Container(
color: Colors.blue,
width: 250.0,
),
),
],
)
複製代碼
const LimitedBox({
Key key,
this.maxWidth = double.infinity,
this.maxHeight = double.infinity,
Widget child,
})
複製代碼
maxWidth:限定的最大寬度,默認值是double.infinity,不能爲負數。ide
maxHeight:同上。函數
先不說其源碼,單純從其做用,前面介紹的SizedBox、ConstrainedBox都相似,都是經過強加到child的constraint,來達到相應的效果。佈局
咱們直接看其計算constraint的代碼學習
minWidth: constraints.minWidth,
maxWidth: constraints.hasBoundedWidth ? constraints.maxWidth : constraints.constrainWidth(maxWidth),
minHeight: constraints.minHeight,
maxHeight: constraints.hasBoundedHeight ? constraints.maxHeight : constraints.constrainHeight(maxHeight)
複製代碼
LimitedBox只是改變最大寬高的限定。具體的佈局代碼以下:動畫
if (child != null) {
child.layout(_limitConstraints(constraints), parentUsesSize: true);
size = constraints.constrain(child.size);
} else {
size = _limitConstraints(constraints).constrain(Size.zero);
}
複製代碼
根據最大尺寸,限制child的佈局,而後將自身調節到child的尺寸。ui
使用場景是不可能清楚了,光是找例子,就花了很多時間。Flutter的一些冷門控件,真的是除了官方的文檔,啥材料都木有。谷歌說這個頗有用,仍是一臉懵逼。這種控件,也有其餘的替代解決方案,LimitedBox能夠達到的效果,ConstrainedBox均可以實現。
A widget that lays the child out as if it was in the tree, but without painting anything, without making the child available for hit testing, and without taking any room in the parent.
Offstage的做用很簡單,經過一個參數,來控制child是否顯示,平常使用中也算是比較經常使用的控件。
Offstage的佈局行爲徹底取決於其offstage參數
另外,當Offstage不可見的時候,若是child有動畫,應該手動停掉,Offstage並不會停掉動畫。
Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > Offstage
複製代碼
Column(
children: <Widget>[
new Offstage(
offstage: offstage,
child: Container(color: Colors.blue, height: 100.0),
),
new CupertinoButton(
child: Text("點擊切換顯示"),
onPressed: () {
setState(() {
offstage = !offstage;
});
},
),
],
)
複製代碼
當點擊切換按鈕的時候,能夠看到Offstage顯示消失。
const Offstage({ Key key, this.offstage = true, Widget child })
複製代碼
offstage:默認爲true,也就是不顯示,當爲flase的時候,會顯示該控件。
咱們先來看下Offstage的computeIntrinsicSize相關的方法:
@override
double computeMinIntrinsicWidth(double height) {
if (offstage)
return 0.0;
return super.computeMinIntrinsicWidth(height);
}
複製代碼
能夠看到,當offstage爲true的時候,自身的最小以及最大寬高都會被置爲0.0。
接下來咱們來看下其hitTest方法:
@override
bool hitTest(HitTestResult result, { Offset position }) {
return !offstage && super.hitTest(result, position: position);
}
複製代碼
當offstage爲true的時候,也不會去執行。
最後咱們來看下其paint方法:
@override
void paint(PaintingContext context, Offset offset) {
if (offstage)
return;
super.paint(context, offset);
}
複製代碼
當offstage爲true的時候直接返回,不繪製了。
到此,跟上面所說的佈局行爲對應上了。咱們必定要清楚一件事情,Offstage並非經過插入或者刪除本身在widget tree中的節點,來達到顯示以及隱藏的效果,而是經過設置自身尺寸、不響應hitTest以及不繪製,來達到展現與隱藏的效果。
當咱們須要控制一個區域顯示或者隱藏的時候,可使用這個場景。其實也有其餘代替的方法,可是成本會高不少,例如直接在tree上插入刪除,可是不建議這麼作。
A widget that imposes different constraints on its child than it gets from its parent, possibly allowing the child to overflow the parent.
OverflowBox這個控件,容許child超出parent的範圍顯示,固然不用這個控件,也有不少種方式實現相似的效果。
當OverflowBox的最大尺寸大於child的時候,child能夠完整顯示,當其小於child的時候,則以最大尺寸爲基準,固然,這個尺寸都是能夠突破父節點的。最後加上對齊方式,完成佈局。
Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > OverflowBox
複製代碼
Container(
color: Colors.green,
width: 200.0,
height: 200.0,
padding: const EdgeInsets.all(5.0),
child: OverflowBox(
alignment: Alignment.topLeft,
maxWidth: 300.0,
maxHeight: 500.0,
child: Container(
color: Color(0x33FF00FF),
width: 400.0,
height: 400.0,
),
),
)
複製代碼
當maxHeight大於height的時候,能夠徹底顯示下來,當maxHeight小於height的時候,則不會會被隱藏掉
構造函數以下:
const OverflowBox({
Key key,
this.alignment = Alignment.center,
this.minWidth,
this.maxWidth,
this.minHeight,
this.maxHeight,
Widget child,
})
複製代碼
alignment:對齊方式。
minWidth:容許child的最小寬度。若是child寬度小於這個值,則按照最小寬度進行顯示。
maxWidth:容許child的最大寬度。若是child寬度大於這個值,則按照最大寬度進行展現。
minHeight:容許child的最小高度。若是child高度小於這個值,則按照最小高度進行顯示。
maxHeight:容許child的最大高度。若是child高度大於這個值,則按照最大高度進行展現。
其中,最小以及最大寬高度,若是爲null的時候,就取父節點的constraint代替。
OverflowBox的源碼很簡單,咱們先來看一下佈局代碼:
if (child != null) {
child.layout(_getInnerConstraints(constraints), parentUsesSize: true);
alignChild();
}
複製代碼
若是child不爲null,child則會按照計算出的constraints進行尺寸的調整,而後對齊。
至於constraints的計算,則仍是上面的邏輯,若是設置的有的話,就取這個值,若是沒有的話,就拿父節點的。
有時候設計圖上出現的角標,會超出整個模塊,可使用OverflowBox控件。但咱們應該知道,不使用這種控件,也能夠完成佈局,在最外面包一層,也能達到同樣的效果。具體實施起來哪一個比較方便,同窗們自行取捨。
A box with a specified size.
比較經常使用的一個控件,設置具體尺寸。
SizedBox佈局行爲相對較簡單:
Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > SizedBox
複製代碼
Container(
color: Colors.green,
padding: const EdgeInsets.all(5.0),
child: SizedBox(
width: 200.0,
height: 200.0,
child: Container(
color: Colors.red,
width: 100.0,
height: 300.0,
),
),
)
複製代碼
構造函數
const SizedBox({ Key key, this.width, this.height, Widget child })
複製代碼
width:寬度值,若是具體設置了,則強制child寬度爲此值,若是沒設置,則根據child寬度調整自身寬度。
height:同上。
SizedBox內部是經過RenderConstrainedBox來實現的。具體的源碼就不解析了,整體思路是,根據寬高值算好一個constraints,而後強制應用到child上。
這個控件,不少場景可使用。可是,能夠替代它的控件也有很多,例如Container、ConstrainedBox等。並且SizedBox就是ConstrainedBox的一個特例。仍是那句話,精簡啊,多提供一些經常使用的,不要提供一大堆重複的,場景不多的控件。
筆者建了一個Flutter學習相關的項目,Github地址,裏面包含了筆者寫的關於Flutter學習相關的一些文章,會按期更新,文章中的代碼也在這個項目中,歡迎你們關注。