从一个路由报错来深入理解Flutter的BuildContext

前言

在使用flutter路由跳转是出现如下错误:

代码:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return new MaterialApp(
      title: 'Test Flutter',
      home: Scaffold(
        body: Center(
          child: FlatButton(
              onPressed: () {
                Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => NewRouter()));
              },
              child: Text('跳转')),
        ),
      ),
    );
  }
}
class NewRouter extends StatelessWidget {
  @override
  Widget build (BuildContext context){
    return Scaffold(
      appBar: AppBar(
        title: Text("hahahha"),
      ),
      body: Center(
        child: Text("new router hahah"),
      ),
    );
  }
}

解决方案

把home部分作为一个新的Widget拆出来就可以了。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return new MaterialApp(
      title: 'Test Flutter',
      home: new MyHomeWidget(),
    );
  }
}

class MyHomeWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return new Scaffold(
      appBar: AppBar(title: Text('new Flutter'),),
      body: new Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              Text('my first flutter app'),
              FlatButton(
                color: Colors.green,
                child: Text('路由跳转'),
                textColor: Colors.white,
                onPressed: () {
                  Navigator.push(context, 
                    MaterialPageRoute(builder: (context){
                      return NewRouter();
                    })
                  );
                },
              )
            ]
          ),

        ),
    );
  }
}
class NewRouter extends StatelessWidget {
  @override
  Widget build (BuildContext context){
    return Scaffold(
      appBar: AppBar(
        title: Text("hahahha"),
      ),
      body: Center(
        child: Text("new router hahah"),
      ),
    );
  }
}

为什么我的Navigator操作会出现当前的context找不到Navigator的情况,为什么拆成新的widget就好了?

那下面就来具体分析一下

我们经常会在应用中打开许多页面,当我们返回的时候,它会先后退到上一个打开的页面,然后一层一层后退,没错这就是一个堆栈。而在Flutter中,则是由Navigator来负责管理维护这些页面堆栈。

//压一个新的页面到屏幕上
Navigator.of(context).push
//把路由顶层的页面移除
Navigator.of(context).pop

通常我们我们在构建应用的时候并没有手动去创建一个Navigator,也能进行页面导航,这又是为什么呢。

没错,这个Navigator正是MaterialApp为我们提供的。但是如果home,routes,onGenerateRoute和onUnknownRoute都为null,并且builder不为null,MaterialApp则不会创建任何Navigator。

BuildContext

每次我们在编写界面部分代码的时候,都是在build函数中进行操作。而build函数则需要默认传入一个BuildContext。我们来看看这到底是啥

abstract class BuildContext {
  /// The current configuration of the [Element] that is this [BuildContext].
  Widget get widget;

  /// The [BuildOwner] for this context. The [BuildOwner] is in charge of
  /// managing the rendering pipeline for this context.
  BuildOwner get owner;
  ...

我们可以看到BuildContext其实是一个抽象类,但是每次build函数传进来的是什么呢。我们来看看构建视图的时候到底发生了什么。


   转载规则


《从一个路由报错来深入理解Flutter的BuildContext》 浅夏晴空 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
vscode中调试Flutter vscode中调试Flutter
前言之前每次启动flutter时首先是要open -a Simulator打开本地的模拟器(我这里是Mac Xcode的iOS模拟器),然后在运行flutter run命令,这是才会把程序运行的模拟器; Launching lib/main
2019-09-17
下一篇 
前端经典面试题大全 前端经典面试题大全
简答题1、什么是防抖和节流?有什么区别?如何实现?参考答案 防抖 触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间 思路: 每次触发事件时都取消之前的延时调用方法 function deboun
2019-09-15
  目录