前言
首先我们看看官方的定义:
[BuildContext] objects are actually [Element] objects. The [BuildContext]
interface is used to discourage direct manipulation of [Element] objects.
[BuildContext] 对象实际上是 [Element] 对象。 [BuildContext] 接口用于阻止直接操作 [Element] 对象。
根据官方这段注释,可以了解到BuildContext 实际上就是 Element 对象,产生的意义主要是为了防止开发者直接操作 Element 对象。
如何使用BuildContext
写一段大家很熟悉的代码
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
}这里有同学好奇,_counter++;不写在setState的回调方法里可以生效吗?答案是可以的。但是我更推荐把和状态更新相关的操作,放在回调里面。这样更加的工程化管理。因为一个项目经过长时期的更新,你可能无法分清,这个方法里面的setState,是不是实际上起作用了,会造成代码冗余。
上面的代码也可以写成这样
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
_counter++;
(context as Element).markNeedsBuild();
}
}为什么会有同样的作用呢?那我们看看setState的源码吧
void setState(VoidCallback fn) {
assert(fn != null);
assert(() {
if (_debugLifecycleState == _StateLifecycle.defunct) {
///......
}
if (_debugLifecycleState == _StateLifecycle.created && !mounted) {
///......
}
return true;
}());
final dynamic result = fn() as dynamic;
assert(() {
if (result is Future) {
///......
]);
}
return true;
}());
_element!.markNeedsBuild();
}那么我们就清楚了,BuildContext实际上就是Widget树中特定位置所对应的实例Element。
使用BuildContext时,应该注意作用域
举个例子
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context){
return MaterialApp(
title: 'Test Flutter',
home: Scaffold(
body: Center(
child: FlatButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => NewWidget()));
},
child: Text('跳转到新页面')),
),
),
);
}
}
class NewWidget extends StatelessWidget {
@override
Widget build (BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text("this is title"),
),
body: Center(
child: Text("this is body"),
),
);
}
}运行一下,发现会报错:提示当前的context找不到Navigator。
我们知道Navigator是MaterialApp为我们提供的,但是当前的调用的context,实际上是MyApp拥有的实例,并不是MaterialApp对应的context。
那我们可以改造一下:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context){
return MaterialApp(
title: 'Test Flutter',
home: Scaffold(
body: Center(
child: Builder(
builder: (context) {
return FlatButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => NewWidget()));
},
child: Text('跳转到新页面')),
),
);
},
),
);
}
}