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,所以不会报错。

原文地址:https://www.cnblogs.com/FdWzy/p/13515228.html