大多数应用程序都具有多个Page或View,并且希望将用户从当前Page平滑过渡到另一个页面。Flutter的路由和导航功能可帮助您管理应用中屏幕之间的命名和过渡。
概述
管理多个页面时有两个核心概念和类:Route和 Navigator。 一个route是一个屏幕或页面的抽象,Navigator是管理route的Widget。Navigator可以通过route入栈和出栈来实现页面之间的跳转。
-
从First页面导航到second页面并返回FIrst页面:
void main() => runApp(new MaterialApp( title: 'Navigation Basics', home: FirstRoute(), )); class FirstRoute extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('First Route'), ), body: Center( child: RaisedButton( child: Text('Open route'), onPressed: () { // Navigate to second route when tapped. Navigator.of(context).push(new MaterialPageRoute( builder: (BuildContext context) => SecondRoute())); }, ), ), ); } } class SecondRoute extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Second Route"), ), body: Center( child: RaisedButton( onPressed: () { // Navigate back to first route when tapped. Navigator.pop(context); }, child: Text('Go back!'), ), ), ); } }
-
从A页面发送数据去B的页面,实际上是通过构造函数传递数据:
class Todo {
final String title;
final String describe;
Todo(this.title, this.describe);
}
class TodosScreen extends StatelessWidget {
final List<Todo> todos;
const TodosScreen({Key key, this.todos}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Todos'),
),
body: new ListView.builder(
itemCount: todos.length,
itemBuilder: (BuildContext context, int index) {
return new ListTile(
title: new Text('todos[index].title'),
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => new DetailScreen(
todo: todos[index],
)));
},
);
}),
);
}
}
class DetailScreen extends StatelessWidget {
final Todo todo;
const DetailScreen({Key key, this.todo}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('${todo.title}'),
),
body: new Padding(
padding: EdgeInsets.all(16.0),
child: new Text(todo.describe),
),
);
}
}
- 等待其他页面返回数据
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Returning Data Demo'),
),
body: Center(child: SelectionButton()),
);
}
}
class SelectionButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: Text('Pick an option, any option!'),
);
}
///运行SelectionScreen页面并且等待SelectionScreen Navigator.pop!返回结果
void _navigateAndDisplaySelection(BuildContext context) async {
///Navigator.push 将在我们调用SelectionScreen页面的Navigator.pop完成后返回一个携带结果数据Future
final result =
await Navigator.push(context, new MaterialPageRoute(builder: (context) {
return SelectionScreen();
}));
// String valResult = await result;
///之后等待SelectionScreen页面返回结果,隐藏任意上一个的SnackBars,并显示并将结果显示在SnackBar
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(new SnackBar(content: new Text(result)));
}
}
class SelectionScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Pick an option'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Yep!" as the result
Navigator.pop(context, 'Yep!');
},
child: Text('Yep!'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Nope!" as the result
Navigator.pop(context, 'Nope.');
},
child: Text('Nope.'),
),
)
],
),
),
);
}
}
- 通过名字路由到其他页面
void main() {
runApp(MaterialApp(
title: 'Named Routes Demo',
// Start the app with the "/" named route. In our case, the app will start
// on the FirstScreen Widget
initialRoute: '/',
routes: {
// When we navigate to the "/" route, build the FirstScreen Widget
'/': (context) => FirstScreen(),
// When we navigate to the "/second" route, build the SecondScreen Widget
'/second': (context) => SecondScreen(),
},
));
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: RaisedButton(
child: Text('Launch screen'),
onPressed: () {
// Navigate to the second screen using a named route
Navigator.pushNamed(context, '/second');
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to the first screen by popping the current route
// off the stack
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
- 跳转页面添加过度动画
class HeroApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Transition Demo',
home: MainScreen(),
);
}
}
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(
'http://pic37.nipic.com/20140113/8800276_184927469000_2.png',
),
),
///transitionsBuilder
///I/flutter (21575): pageBuilder
///I/flutter (21575): transitionsBuilder
///I/flutter (21575): transitionsBuilder
///I/flutter (21575): transitionsBuilder
onTap: () {
Navigator.push(
context,
new PageRouteBuilder(
transitionDuration: new Duration(seconds: 2),
transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
print('transitionsBuilder 这里会一直执行到动画结束');
// return SlideTransition(
// position: new Tween<Offset>(
// begin: const Offset(0.0, 1.0),
// end: Offset.zero,
// ).animate(animation),
// child: SlideTransition(
// position: Tween<Offset>(
// begin: Offset.zero,
// end: const Offset(0.0, 1.0),
// ).animate(secondaryAnimation),
// child: child,
// ),
// );
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),
child: child, // child is the value returned by pageBuilder
);
},
pageBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation) {
print('pageBuilder');
return new DetailScreen();
}));
},
),
);
}
}
class DetailScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
child: Center(
child: Hero(
tag: 'imageHero',
child: Image.network(
'http://pic37.nipic.com/20140113/8800276_184927469000_2.png',
),
),
),
onTap: () {
Navigator.pop(context);
},
),
);
}
}
-
自定义Router
class CustomRoute extends PageRouteBuilder { final Widget widget; CustomRoute(this.widget) : super( // 设置过度时间 transitionDuration: Duration(seconds: 1), // 构造器 pageBuilder: ( // 上下文和动画 BuildContext context, Animation<double> animaton1, Animation<double> animaton2, ) { return widget; }, transitionsBuilder: ( BuildContext context, Animation<double> animaton1, Animation<double> animaton2, Widget child, ) { // 旋转加缩放动画效果 return RotationTransition( turns: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( parent: animaton1, curve: Curves.fastOutSlowIn, )), child: ScaleTransition( scale: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( parent: animaton1, curve: Curves.fastOutSlowIn)), child: child, ), ); }); }
使用很简单:
final result =
await Navigator.push(context, new CustomRoute(SelectionScreen()));
// String valResult = await result;
///之后等待SelectionScreen页面返回结果,隐藏任意上一个的SnackBars,并显示并将结果显示在SnackBar
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(new SnackBar(content: new Text(result)));
最后附上demo链接
网友评论