flutter中有很多種Builder,雖然所有的builder都是構造器,但是不同的builder之間還是有很多差距的。今天我們來詳細介紹一下Builder,LayoutBuilder,StatefulBuilder這幾個builder的使用。
Builder是flutter中最常用的builder,它是一個StatelessWidget,如下所示:
class Builder extends StatelessWidget
我們看下它的建構函式:
const Builder({
Key? key,
required this.builder,
}) : assert(builder != null),
super(key: key);
可以看到Builder和普通的StatelessWidget的最大的差別就是需要傳入一個builder屬性,這個builder是一個WidgetBuilder型別的屬性,
WidgetBuilder是這樣定義的:
typedef WidgetBuilder = Widget Function(BuildContext context);
可以看到WidgetBuilder實際上是一個返回Widget的函數,這個函數在Builder被包含在parent's build方法中的時候,會被呼叫。
那麼使用Builder和普通的StatelessWidget有什麼區別呢?
我們舉個例子,首先是在Scaffold中直接包含一個包括TextButton的Center widget,如下所示:
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextButton(
child: Text('TextButton'),
)
),
);
}
上面的Center也可以使用Builder來封裝:
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context) {
return Center(
child: TextButton(
child: Text('TextButton'),
),
);
},
),
);
}
初看起來兩者沒有太大的區別,但是不同的是在下面的例子中,我們使用了Builder來構建body。
Builder的builder方法中我們傳入了一個context,這個context是當前builder的context,我們可以通過這個context來獲取到一些平時比較難獲取到的物件。
對於Scaffold來說,它提供了一個of方法,可以根據傳入的context來找到離context最近的Scaffold。這也是我們使用builder的目的:
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context) {
return Center(
child: TextButton(
onPressed: () {
print(Scaffold.of(context).hasAppBar);
},
child: Text('TextButton'),
),
);
},
),
);
}
如上,我們可以在builder中,呼叫Scaffold.of(context)
方法來獲取對應的Scaffold物件。
如果只是使用普通的StatelessWidget的話,是沒法拿到Scaffold物件的。
上一節我們提到的Buidler實際上是一個StatelessWidget,表明builder是無狀態的。
而StatefulBuilder則和Builder不同,它是有狀態的:
class StatefulBuilder extends StatefulWidget
可以看到StatefulBuilder繼承自StatefulWidget。
和Builder很類似,StatefulBuilder也有一個builder屬性,不過這個builder屬性的型別是StatefulWidgetBuilder:
typedef StatefulWidgetBuilder = Widget Function(BuildContext context, StateSetter setState);
可以看到StatefulWidgetBuilder被呼叫的時候,不僅傳入了BuildContext,還同時呼叫了setState方法。
StateSetter方法會導致Widget重構。
如果我們建立的widget是一個StatefulWidget的話,那麼就可以嘗試使用StatefulBuilder來代替:
Widget build(BuildContext context) {
return Center(
child: Builder(
builder: (BuildContext context) {
int clicked = 0;
return Center(
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return TextButton(onPressed: (){
setState(() => {clicked = 1 });
},
child: Text('TextButton'));
}),
);
},
),
);
}
Builder可以傳遞BuildContext, StatefulBuilder可以傳遞StateSetter,LayoutBuilder和上面提到的兩個Builder很類似,不同的是LayoutBuilder可以提供父widget的大小。
我們先來看下LayoutBuilder的定義:
class LayoutBuilder extends ConstrainedLayoutBuilder<BoxConstraints>
可以看到LayoutBuilder繼承的類是不同的。
LayoutBuilder需要傳入一個builder屬性,這個builder是一個LayoutWidgetBuilder物件:
typedef LayoutWidgetBuilder = Widget Function(BuildContext context, BoxConstraints constraints);
具體的使用方法和Builder很類似,不同的是我們可以根據傳入的BoxConstraints來進行對應的邏輯判斷。
看一個具體的例子:
class LayoutBuilderApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
if (constraints.maxWidth > 500) {
return buildWidget1();
} else {
return buildWidget2();
}
},
);
}
Widget buildWidget1() {
return Center(
child: Container(
height: 700.0,
width: 700.0,
color: Colors.blue,
),
);
}
Widget buildWidget2() {
return Center(
child: Container(
height: 200.0,
width: 200.0,
color: Colors.yellow,
),
);
}
上面的例子中,我們根據BoxConstraints的大小,來返回不同的Widget元件。
這在某些情況下是非常有用的。
本文介紹了三個常用的Builder,大家可以仔細體會。
本文的例子:https://github.com/ddean2009/learn-flutter.git
更多內容請參考 https://www.cnblogs.com/flydean/p/www.flydean.com
最通俗的解讀,最深刻的乾貨,最簡潔的教學,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!