准备
Flutter 版本:2.5.1
准备了 3 个页面,代码如下
页面一:
class FirstPage extends StatelessWidget {
const FirstPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
"second": (content) => const SecondPage() // 跳转第 2 个页面的路由
},
home: Scaffold(
appBar: AppBar(
title: const Text("Haocold"),
),
body: const FirstBody(),
),
);
}
}
class FirstBody extends StatelessWidget {
const FirstBody({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, "second"); // 跳转第 2 个页面
},
child: const Text("下一个页面"));
}
}
页面二:
class SecondPage extends StatelessWidget {
const SecondPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
routes: {"third": (content) => const ThirdPage()}, // 跳转第 3 个页面的路由
home: Scaffold(
appBar: AppBar(
title: const Text("第二个页面"),
leading: BackButton(
onPressed: () {
Navigator.pop(context);
},
),
),
body: const SecondBody(),
),
);
}
}
class SecondBody extends StatelessWidget {
const SecondBody({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, "third"); // 跳转第 3 个页面
},
child: const Text("下一个页面"));
}
}
页面三:
class ThirdPage extends StatelessWidget {
const ThirdPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text("第三个页面"),
leading: BackButton(
onPressed: () {
Navigator.pop(context);
},
),
),
body: ThirdBody(scontext: context),
),
);
}
}
class ThirdBody extends StatelessWidget {
const ThirdBody({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
Navigator.pop(context); // 返回上一个页面
},
child: const Text("上一个页面"));
}
}
返回上一个界面,黑屏了?
原因是 context 造成的 跟之前那篇文章说的一样,参见 => 原文
于是,把上级的 context 传进来 代码改动如下:
......
body: ThirdBody(scontext: context),
),
);
}
}
class ThirdBody extends StatelessWidget {
const ThirdBody({Key? key, required this.scontext}) : super(key: key);
final BuildContext scontext; // 接收传入的 context
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
Navigator.pop(scontext); // 这里使用传入的 context
},
child: const Text("上一个页面"));
}
}
这次就能返回第 2 个页面了。
侧滑返回,直接到根视图了?
侧滑返回,不应该返回第 2 个界面么? 还是 context 造成的 跳转第 2 个页面相关的 context 与 跳转第 3 个页面相关的 context 不是 同一个!
所以,还是得把上级的 context 传进来
......
body: SecondBody(scontext: context),
),
);
}
}
class SecondBody extends StatelessWidget {
const SecondBody({Key? key, required this.scontext}) : super(key: key);
final BuildContext scontext; // 接收传入的 context
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
Navigator.pushNamed(scontext, "third");
},
child: const Text("下一个页面")); // 这里使用传入的 context
}
}
并且 要把第 2 个页面的
routes: {"third": (content) => const ThirdPage()}, // 删掉
合并到第 1 个页面的 routes
routes: {
"second": (content) => const SecondPage(),
"third": (content) => const ThirdPage(),
}
这样就可以,侧滑返回上一个页面了
深入了解 BuildContext
官方文档:
[BuildContext] objects are actually [Element] objects.
The [BuildContext] interface is used to discourage direct manipulation of [Element] objects.
更多参见 => 文章
部分摘抄:
视图树装载过程
StatelessWidget
- 首先它会调用StatelessWidget的 createElement 方法,并根据这个widget生成StatelesseElement对象。
- 将这个StatelesseElement对象挂载到element树上。
- StatelesseElement对象调用widget的build方法,并将element自身作为BuildContext传入。
StatefulWidget
- 首先同样也是调用StatefulWidget的 createElement方法,并根据这个widget生成StatefulElement对象,并保留widget引用。
- 将这个StatefulElement挂载到Element树上。
- 根据widget的 createState 方法创建State。
- StatefulElement对象调用state的build方法,并将element自身作为BuildContext传入。
- 所以我们在build函数中所使用的context,正是当前widget所创建的Element对象。
当我们在 build 函数中使用Navigator.of(context)的时候
这个context实际上是通过 MyApp 这个widget创建出来的Element对象
而of方法向上寻找祖先节点的时候(MyApp的祖先节点)并不存在MaterialApp,也就没有它所提供的Navigator
所以当我们把Scaffold部分拆成另外一个widget的时候
我们在FirstPage的build函数中
获得了FirstPage的BuildContext
然后向上寻找发现了MaterialApp
并找到它提供的Navigator
于是就可以愉快进行页面跳转了
笔记从未如此简单
一步到位
|