flutter context踩坑
下面代码有三个button,内容都是一样的,只不过包装方式不同。
第一个是没有包装的,第二个用Builder包了一层,第三个封装成了StatelessWidget。
运行一下,第一个button会报如下错误:
是说调用的Scaffod.of(context)找不到Scaffold。
import 'package:flutter/material.dart'; void main() => runApp(BuilderApp()); class BuilderApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: BuilderHomePage(), ); } } class BuilderHomePage extends StatefulWidget { @override _BuilderHomePageState createState() => _BuilderHomePageState(); } class _BuilderHomePageState extends State<BuilderHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Hello"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ RaisedButton( onPressed: () { Scaffold.of(context).showSnackBar( new SnackBar(content: Text("Hello SnackBar1"))); }, child: Text("Test"), ), Builder( builder: (BuildContext context) { return RaisedButton( onPressed: () { Scaffold.of(context).showSnackBar( new SnackBar(content: Text("Hello SnackBar2"))); }, child: Text("Builder SnackBar"), ); }, ), WidgetTest() ], ), ), ); } } class WidgetTest extends StatelessWidget { @override Widget build(BuildContext context) { return Container( child: RaisedButton( onPressed: () { Scaffold.of(context).showSnackBar( new SnackBar(content: Text("Hello SnackBar3"))); }, child: Text("No Builder SnackBar"), ), ); } }
分析一下:
这是Scaffold.of(context)的源码
可以看到这个方法返回的是findAncestorStateOfType()。其实所有.of(context).xxx这样的方法都是调用这个东西。
点进去看看:
可以看到这个方法是在依次向上遍历该widget的祖先,直到找到一个符合参数类型的祖先就退出。
注意最开始赋值是把当前widget的_parent赋给了ancestor,所以是从当前widget的父节点开始找的。
那么就很容易判断了:
第一个button的context复用了build函数的context(android studio很贴心的会高亮两个context的连接关系)
第二个button用Builder套了一层,它的context是Builder的builder函数的参数context
第三个button的context是StatelessWidget的build函数参数的context,就不截图了。
由于第一个button的context和scaffold是同一个,所以从它的_parent往上找肯定找不到scaffold,所以报错。
另外两个button都是scaffold的子节点,他俩的_parent恰好就是scaffold,所以不会报错。
进击的小🐴农