天天看點

flutter系列之:builder為構造器而生

目錄

  • ​​簡介​​
  • ​​Builder​​
  • ​​StatefulBuilder​​
  • ​​LayoutBuilder​​
  • ​​總結​​

簡介

flutter中有很多種Builder,雖然所有的builder都是構造器,但是不同的builder之間還是有很多差距的。今天我們來詳細介紹一下Builder,LayoutBuilder,StatefulBuilder這幾個builder的使用。

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對象的。

StatefulBuilder

上一節我們提到的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'));
                  }),
                );
        },
      ),
    );
  }      

LayoutBuilder

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​​

最通俗的解讀,最深刻的幹貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!