写点什么

flutter 系列之:flutter 中的 builder

作者:程序那些事
  • 2022 年 6 月 20 日
  • 本文字数:2413 字

    阅读完需:约 8 分钟

简介

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

发布于: 刚刚阅读数: 3
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
flutter系列之:flutter中的builder_flutter_程序那些事_InfoQ写作社区