文档非常混乱和模糊。它是这样的:
Builder类
一个柏拉图式小部件,它调用一个闭包来获取其子小部件。
这是我的问题:
答案 0 :(得分:16)
经过长时间的互联网研究,我收集了一些小片段,并将它们组合在一起,以清晰,清晰地解释了Builder类的作用。
术语:
根据官方flutter文档, Builder类定义为:
一个柏拉图式小部件,它调用一个闭包来获取其子小部件。
柏拉图表示这种类型的最简单的东西。术语 closure 只是 lambda 函数的另一个名称。
目的:
这将是一个冗长的解释,但是请忍受我:
在Flutter框架中,每个小部件都有一个 build 方法,该方法接受 BuildContext 参数:
小部件构建( BuildContext上下文 ){ ...}
我们必须记住, 上下文 对象是由框架自动传递到小部件的 build 函数的。由于框架是自动处理的,因此没有任何理由让小部件具有需要接受 context build 之外)。 > 参数。
因此,如果您试图将特定的 context 对象传递给孩子,则将无法通过。您不能调用build()并手动传递自己的 context 对象。我的意思是,可以,但是您将两次调用build函数:
那么,如何传递特定的 context 对象?这是 Builder 类的来源。 Builder 类的目的仅仅是构建并返回子窗口小部件。这与其他任何小部件有何不同?啊哈! Builder 类使您可以将特定的 context 对象向下传递给其子级。 Builder 类基本上是您自己设置的构建函数。
我为什么需要传递特定的 context 对象?让我们看一个例子:
让我们说我们想向返回的新 Scaffold 父窗口小部件中添加一个新的 SnackBar 小部件:
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Container(),
/// Scaffold doesn't exist in this context here
/// because the context thats passed into 'build'
/// refers to the Widget 'above' this one in the tree,
/// and the Scaffold doesn't exist above this exact build method
///
/// This will throw an error:
/// 'Scaffold.of() called with a context that does not contain a Scaffold.'
floatingActionButton: new FloatingActionButton(onPressed: () {
Scaffold.of(context).showSnackBar(
new SnackBar(
content: new Text('SnackBar'),
),
);
}));
}
上面的代码无效。 Scaffold.of(context)函数将找不到 Scaffold ,因为:
那么,我们如何让childre SnackBar小部件访问父 Scaffold 小部件?我们使用 Builder 类传递 Scaffold 小部件的上下文:
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Container(),
/// Builders let you pass context
/// from your *current* build method
/// Directly to children returned in this build method
///
/// The 'builder' property accepts a callback
/// which can be treated exactly as a 'build' method on any
/// widget
floatingActionButton: new Builder(builder: (BuildContext context) {
return new FloatingActionButton(onPressed: () {
Scaffold.of(context).showSnackBar(
new SnackBar(
backgroundColor: Colors.blue,
content: new Text('SnackBar'),
),
);
});
}),
);
}
请记住, Builder 类的构造函数:
Builder({键,@ required WidgetBuilder构建器})
通过将其构件委托给通过其构造函数传递的回调函数来创建构件。
因此,在代码中:
new Builder(builder: (BuildContext context){ ... });
我们提供了一个闭包,
基本上,您提供了自己的构建功能。此闭包中的 BuildContext上下文参数是Scaffold的上下文!宝贝!
基本上就是这样。 Flutter文档完全没有提供完整的解释。我觉得比破译Flutter文档,破译古代象形文字要容易得多。
我希望这对目前正在学习Flutter的单调乏味的人有所帮助。
答案 1 :(得分:4)
简单定义?
这个Builder小部件就像它的名字所暗示的那样;用于创建带有“新上下文”的子窗口小部件。
技术定义?
此构建器具有 builder属性,并且此属性接受 WidgetBuilder typedef (WidgetBuilder typedef是用于使用新上下文创建(返回)窗口小部件的函数的签名)< / p>
如果您想了解 WidgetBuilder typedef ,请使用此链接➡{https://api.flutter.dev/flutter/widgets/WidgetBuilder.html
用法:
1 。当 Scaffold小部件和 Scaffold.of方法在同一构建方法中时。
[当时scaffold.of方法找不到壁橱Scaffold小部件,因为两者都是 在 相同的上下文,通过在build方法内创建新的上下文,您可以解决此问题,这就是为什么 我们使用Builder Widget来创建带有New BuildContext的控件。 ]
下面的代码显示了想要在同一构建方法use
中使用 Scaffold.of 和 Scaffold 小部件时Builder小部件的实际用法。(仔细查看这些注释,它将帮助您理解上下文)
Widget build(BuildContext context) { // context - 1
return Scaffold(
appBar: AppBar(
title: Text('Demo')
),
body: Builder(
// Create an inner BuildContext so that the onPressed methods
// can refer to the Scaffold with Scaffold.of().
builder: (BuildContext context) { // context - 2
return Center(
child: RaisedButton(
child: Text('SHOW A SNACKBAR'),
onPressed: () {
Scaffold.of(context).showSnackBar(SnackBar( // here context is (context- 2)
content: Text('Have a snack!'),
));
},
),
);
},
),
);
}
2 。当 Theme.of 方法和 Theme 小部件处于同一构建方法中时。
[此处的目的也与上述1相同]
下面的代码显示了当您要在同一构建方法use
中使用 Theme.of 和 Theme 小部件时,Builder小部件的实际用法。@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
body: Builder(
// Create an inner BuildContext so that we can refer to
// the Theme with Theme.of().
builder: (BuildContext context) {
return Center(
child: Text(
'Example',
style: Theme.of(context).textTheme.title,
),
);
},
),
);
}
额外点
我们可以在许多实例上看到的buider属性(WidgetBuilder typedef)
在该代码部分的下方显示,“ MaterialPageRoute ”如何使用构建器属性获取该路线的小部件
Navigator.push(context, MaterialPageRoute<void>(
builder: (BuildContext context) { //here
return Scaffold(
appBar: AppBar(title: Text('My Page')),
body: Center(
child: FlatButton(
child: Text('POP'),
onPressed: () {
Navigator.pop(context);
},
),
),
);
},
));
答案 2 :(得分:3)
它基本上将将构建窗口小部件的功能转换为窗口小部件。
在需要传递小部件但仅具有返回小部件的功能的地方,可以使用Builder
小部件。
bool bar;
Widget createFooOrBarWidget() {
if(bar) {
return BarWidget();
}
return FooWidget();
}
Widget build(BuildContext context) =>
Container(child: Builder((context) => createFooOrBarWidget()));
您也可以使用
Widget build(BuildContext context) =>
Container(child: createFooOrBarWidget());
但是前者会延迟Foo或Bar小部件的创建,直到实际调用build
为止。
答案 3 :(得分:0)
observation: you might like to give the inner context arg a different name in order to reinforce the fact that it is the one passed to the FAB, i.e. the buildContext actually corresponds to a widget's parent, which is why Scaffold.of(context passed to FAB) => scaffold widget.
Hmm this stuff is a real learning curve for old GWT devs, but moving from Java to Dart is definitely a huge step fwd. Thanks for your work here.