Flutter 学习笔记 10 - 路由和导航(2)
2019-01-05 本文已影响5人
三流之路
返回数据
如果要返回数据,pop 方法还有一个重载方法,有个可选的位置参数,用于传递返回的数据。
static bool pop<T extends Object>(BuildContext context, [ T result ]) {
return Navigator.of(context).pop<T>(result);
}
比如 Navigator.pop(context, "返回内容");
,然后将 push 放到异步函数里,返回值就是其它页面返回的 result。
class FirstScreen extends StatelessWidget {
// 异步函数
_toSecond(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen(title: "标题", content: "内容")),
);
// 等待页面返回,数据存为 result
print('result=$result');
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("$result")));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: RaisedButton(
child: Text('content'),
onPressed: () {
_toSecond(context);
},
),
),
);
}
}
结果日志打印出来了,但是 SnackBar 未显示,看错误日志以及官网有效的代码,发现要把 FirstScreen 这个 widget 放到 Scaffold 的 body 位置才行,SnackBar 的 Scaffold.of(context)
参数有问题。
尝试将 FirstScreen 改成 StatefulWidget。
class FirstScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return FirstState();
}
}
class FirstState extends State<FirstScreen> {
int count = 0;
var content = 'content';
_toSecond(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen(title: "标题", content: "内容${++count}")), // 每次传递的内容有变化
);
// 当从其它页面返回时,重新设置 content 以让当前页面发生变化
setState(() {
content = result;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: RaisedButton(
// 使用 content 变量内容,从其它页面返回时会发生变化
child: Text('$content'),
onPressed: () {
_toSecond(context);
},
),
),
);
}
}
然后修改 SecondScreen,返回传进来的值。
class SecondScreen extends StatelessWidget {
final String title;
final String content;
// 构造方法接收两个参数
SecondScreen({Key key, @required this.title, @required this.content}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: RaisedButton(
onPressed: () {
// 返回传进来的内容
Navigator.pop(context, "返回$content");
},
child: Text(content),
),
),
);
}
}
2019_01_05_10_32_54.gif
通过给 route 命名来跳转
MaterialApp(
// initialRoute 表示当前要显示的内容
initialRoute: '/',
routes: {
// 根路径表示 FirstScreen
'/': (context) => FirstScreen(),
'/second': (context) => SecondScreen(),
},
);
测试发现必须要在 MaterialApp 里用,initialRoute 表示要显示的内容,不允许写 home 了。
页面跳转时使用
Navigator.pushNamed(context, '/second');
// 代替下面的写法
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => FirstScreen()),
// );
返回依然用 Navigator.pop
方法。
在不同页面对一个 Widget 做动画
类似 Android 的转场动画。
将两个页面都要显示的 Widget 用 Hero 这个 Widget 包裹一层。
Hero(
tag: 'imageHero',
child: Image.network(
'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
),
);
在两个页面 tag 必须一样,child 是要做动画的内容。
class MainScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Main Screen'),
),
body: GestureDetector(
child: Hero(
tag: 'imageHero',
child: Image.network(
'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
),
),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return DetailScreen();
}));
},
),
);
}
}
class DetailScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
child: Center(
child: Hero(
tag: 'imageHero',
child: Image.network(
'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
),
),
),
onTap: () {
Navigator.pop(context);
},
),
);
}
}
第一个页面中图片在上边,到了第二个页面,图片到了中间。
2019_01_05_18_17_27.gif修改第二个页面的图片大小
child: Hero(
tag: 'imageHero',
child: Container(
height: 100,
margin: const EdgeInsets.symmetric(horizontal: 10.0),
child: Image.network(
'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
),
)
),
2019_01_05_18_22_01.gif