文档非常混乱和含糊。以下是它的说明:
Builder类
一个调用闭包以获取其子widget的形式化小部件。
以下是我的问题:
- 他们所说的“形式化”是什么意思?
- 他们所说的“闭包”是什么意思?
- 这个类的目的究竟是什么?
文档非常混乱和含糊。以下是它的说明:
Builder类
一个调用闭包以获取其子widget的形式化小部件。
以下是我的问题:
@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,原因如下:
那么,我们如何使子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({Key key, @required WidgetBuilder builder})
通过将其构建委托给通过构造函数传递的回调函数来创建小部件。
因此,在以下代码中:
new Builder(builder: (BuildContext context){ ... });
我们提供了一个闭包,其中:
基本上,你提供了自己的构建函数。这个闭包中的BuildContext context参数是Scaffold的context!太棒了!
就是这样。Flutter文档根本没有提供很详细的解释。我觉得我要比解码Flutter文档更容易理解古代象形文字。
总结:对于那些仍然难以理解这个概念的人,让我用更简明的方式来解释。Builder函数只是允许你获得并使用包含Builder widget的父widget(即Scaffold)的context对象。在上面的示例中,它是new Scaffold() widget。记住,唯一可用的context对象是父widget(即Scaffold)的,因为当前widget (Scaffold)还没有被创建。我希望这能帮助那些还在纠结的人。
它基本上将构建小部件的函数转换为小部件。
当您需要传递小部件但只有返回小部件的函数时,可以使用 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
方法。
build
就不能有小部件。当Flutter重新构建视图时,会对每个小部件调用build
方法。 - Günter Zöchbauer简单定义
如其名,Builder Widget是用来创建一个带有“新上下文”的子Widget的。
技术定义
这个Builder Widget具有一个builder属性,该属性接受WidgetBuilder typedef(WidgetBuilder typedef是一个函数签名,用于创建(返回)一个带有新上下文的Widget)
如果您想了解WidgetBuilder typedef,请使用此链接➡https://api.flutter.dev/flutter/widgets/WidgetBuilder.html
用法:
1. 当Scaffold widget和Scaffold.of方法在同一构建方法中时。
[ 这时scaffold.of方法找不到最近的Scaffold widget,因为两者在相同的上下文中,通过在build方法内创建新上下文,可以解决这个问题,这就是为什么我们使用Builder Widget创建带有新BuildContext的Widget。]
下面的代码展示了使用Builder Widget的真实用例,当您想要在同一构建方法中使用Scaffold.of和Scaffold widget时。
(仔细查看这些注释-它将帮助您理解上下文)
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相同]
以下代码展示了Builder小部件的实际用法,当您想要在同一个构建方法中使用Theme.of方法和Theme小部件时。
@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 property (WidgetBuilder typedef)
。
下面的代码部分展示了,MaterialPageRoute 如何使用 builder property
来获取该路由的小部件(widget)。
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);
},
),
),
);
},
));