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

2022-10-18 12:01:46

簡介

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

更多內容請參考 https://www.cnblogs.com/flydean/p/www.flydean.com

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

歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!