乐趣区

关于flutter:flutter系列之builder为构造器而生

简介

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

更多内容请参考 www.flydean.com

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

退出移动版