flutter入坑,使用Navigator跳转页面

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // 主方法
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Navigator跳转页面')),
        body: Center(
          child: GestureDetector(
            onTap: () {
              Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext ctx) => FirstPage()));
            },
            child: Text('Hello World!',textDirection: TextDirection.ltr),
          ),
        ),
      )
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
      child: GestureDetector(
        onTap: () {
          Navigator.pop(context);
        },
        child: Text('我是第二个页面',textDirection: TextDirection.ltr),
      ),
    );
  }
}

在使用Navigator.of的时候,传入context时会报错。

Navigator operation requested with a context that does not include a Navigator

The context used to push or pop routes from the Navigator must be that of a widget that is a

descendant of a Navigator widget.

flutter入坑,使用Navigator跳转页面_第1张图片

看样子就是传入的context不对,刚入坑对BuildContext也不熟悉,只能看看BuildContext具体是什么意思了。下面是对BuildContext类的翻译,反正意思是那个意思。

表示了一个widget在widget树中的位置引用。

些类提供了一组可以使用StatelessWidget.build方法和State对象方法的方法。

BuildContext对象将传入到WidgetBuilder函数里(例如StatelessWidget.build),并且可以从State.context成员变量中获取。一些静态函数(如showDialog,Theme.of等等)也采用构建上下文,以便能使用widget执行操作,或者获取给定的上下文数据。

每个widget都有自己的BuildContext,它成为了StatelessWidget.build或State.build函数返回的widget的父级。(同样,RenderObjectWidgets的任何子代的父代)

特别是,这意味着在build方法中,build方法的widget的构建上下文,与build方法返回的widget的构建上下文不一样。这可能会导致一些棘手的问题。例如,Theme.of(context)寻找给定上下文中最近的封装了Theme的部件。如果一个Q部件的build方法,在返回的widget树中包含了Theme部件,并将它自己的context传入Theme.of方法中,Q部件的build方法将不会找到Theme对象,相反,它会找到Q部分祖先的Theme对象。如果需要返回树的子部分的构建上下文,可以使用Builder部件:Builder本身的上下文对象将会作为参数传到Builder.builder的回调函数中。

举例来说,在下面的代码片段中,ScaffoldState.showSnackBar方法在Scaffold部件中的Builder本身的回调函数中调用,如果不使用Builder部件,而是使用build方法的context参数,Scaffold部件不会被找到,Scaffold.of函数方法会返回null。

  @override
  Widget build(BuildContext context) {
    // 这里, Scaffold.of(context) 返回 null
    return Scaffold(
      appBar: AppBar(title: Text('Demo')),
      body: Builder(
        builder: (BuildContext context) {
          return FlatButton(
            child: Text('BUTTON'),
            onPressed: () {
              // 这里, Scaffold.of(context) 返回当前创建的Scaffold
              Scaffold.of(context).showSnackBar(SnackBar(
                content: Text('Hello.')
              ));
            }
          );
        }
      )
    );
  }

随着widget在树上的移动,特定的widget的BuildContext可以随时改变位置。因为这个原因,类方法中返回的值不应该在执行单个同步方法后被缓存。

BuildContext实际上就是Element对象,BuildContext接口是用来阻止直接操作Element对象的。

其实就是讲了两种获取context的方法,一种就是widget的build方法的参数来获取,还有一种就是使用Builder部件参数的builder函数回调参数,来获取一个Builder自身的context对象。

那为什么会报错呢?我不是使用了build方法中的context对象来寻找Navigator对象了吗?回头翻看了一下Navigator.of的源码:

flutter入坑,使用Navigator跳转页面_第2张图片

flutter入坑,使用Navigator跳转页面_第3张图片

这种情况应该是使用context找符合要求的祖先navigator没有找到,并且我们的MyApp还继承了StatelessWidget,所以更不符合要求了,先按照这种情况,我们将Scaffold抽出来看看。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // 主方法
  @override
  Widget build(BuildContext context) {
    print(context.findRootAncestorStateOfType());
    return MaterialApp(
      home: HomePage()
    );
  }
}

class HomePage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Navigator跳转页面')),
      body: Center(
        child: GestureDetector(
          onTap: () {
            print(context.findRootAncestorStateOfType());
            Navigator.of(context,rootNavigator: true).push(MaterialPageRoute(builder: (BuildContext ctx) => FirstPage()));
          },
          child: Text('Hello World!',textDirection: TextDirection.ltr),
        ),
      ),
    );
  }

}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
      child: GestureDetector(
        onTap: () {
          Navigator.pop(context);
        },
        child: Text('我是第二个页面',textDirection: TextDirection.ltr),
      ),
    );
  }
}

 

还有一种方法就是使用Builder来获取context,先上一版改过的代码:

class MyApp extends StatelessWidget {
  // 主方法
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Builder(
        builder: (context){
          // 这里使用builder回调获取Builder本身的context
          return Scaffold(
            appBar: AppBar(title: Text('Navigator跳转页面')),
            body: Center(
              child: GestureDetector(
                onTap: () {
                  Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext ctx) => FirstPage()));
                },
                child: Text('Hello World!',textDirection: TextDirection.ltr),
              ),
            ),
          );
        },
      )
    );
  }
}

 

你可能感兴趣的:(flutter入坑)