Chapter 2: Flutter Navigation: Getting Started
Flutter Navigation: Getting Started
大綱
Getting Started
Creating a Widget to Navigate To
Navigation using Routes
Popping the Stack
Returning a Value
Creating Custom Transitions
Where to Go From Here?
Creating a Widget to Navigate To
create a new file named memberwidget.dart:
import 'package:flutter/material.dart';
import 'member.dart';
class MemberWidget extends StatefulWidget {
// Add a Member property for the widget.
final Member member;
MemberWidget(this.member) {
if (member == null) {
// Make sure that the member argument is not-null in the widget constructor
throw ArgumentError("member of MemberWidget cannot be null. Received: '$member'");
}
}
@override
// Use a MemberState class for the state, passing along a Member object to the MemberState.
createState() => MemberState(member);
}
class MemberState extends State<MemberWidget> {
final Member member;
// given MemberState a Member property and a constructor.
MemberState(this.member);
@override
Widget build(BuildContext context) {
// creating a Scaffold, a material design container, which holds an AppBar and a Padding with a child Image for the member avatar.
return Scaffold(
appBar: AppBar(
title: Text(member.login),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Image.network(member.avatarUrl)
),
);
}
}
Navigation using Routes
Navigation in Flutter is centered around the idea of routes.
Routes are similar in concept to the routes that you would use in a REST API, where each route is relative to some root. The widget
main()
acts like the root in your app (“/”) and all other routes are relative to that one.One way to use routes is with
PageRoute
Since you’re working with a Flutter MaterialApp, you’ll use the
MaterialPageRoute
import 'memberwidget.dart';
_pushMember(Member member) {
// using Navigator to push a new MaterialPageRoute onto the stack, and you build the MaterialPageRoute using a MemberWidget
// MemberWidget利用收到member資料產生新頁面
// MaterialPageRoute再把MemberWidget進行push動作
Navigator.push(context,
MaterialPageRoute(builder: (context) => MemberWidget(member)));
}
Widget _buildRow(int i) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: ListTile(
title: Text("${_members[i].login}", style: _biggerFont),
leading: CircleAvatar(
backgroundColor: Colors.green,
backgroundImage: NetworkImage(_members[i].avatarUrl)
),
// Add onTap here:
onTap: () {
// 將member的資料結構傳入
_pushMember(_members[i]);
},
)
);
}
Popping the Stack
在memberwidget增加一個back button, 來進行pop動作
- body: Padding(
- padding: EdgeInsets.all(16.0),
- child: Image.network(member.avatarUrl)
- ),
+ body: Column(
+ children: [
+ Image.network(member.avatarUrl),
+ IconButton(
+ icon: Icon(Icons.arrow_back, color: Colors.green, size: 48.0),
+ onPressed: () {
+ // set its onPressed value to call Navigator and pop the stack
+ Navigator.pop(context);
+ },
+ )
+ ],
+ )
Returning a Value
Routes can return values
Add the following private
async
method toMemberState
_showOKScreen(BuildContext context) async {
// push a new MaterialPageRoute onto the stack with a type parameter of bool
// using await when pushing the new route, which waits until the route is popped.
// the bool type parameter in MaterialPageRoute, which you can replace with any other type you want coming back from the route
bool value = await Navigator.push(context, MaterialPageRoute<bool>(builder: (BuildContext context) {
return Padding(
padding: const EdgeInsets.all(32.0),
child: Column(children: <Widget>[
// In the calls to pop(),
// you pass a return value of true if the user tapped the “OK” text on the screen, and false if the user tapped “NOT OK”.
// If the user presses the back button instead, the value returned is null.
GestureDetector(
child: Text('OK'),
onTap: () {
// 這裡的true會透過MaterialPageRoute<bool>回傳到value中
Navigator.pop(context, true);
}),
GestureDetector(
child: Text('Not OK'),
onTap: () {
Navigator.pop(context, false);
})
]));
}));
var alert = AlertDialog(
// 根據value來確定是哪個按鈕被觸發
content: Text((value != null && value) ? "OK was pressed" : "NOT OK or BACK was pressed"),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.pop(context);
})
],
);
// call showDialog() to show the alert
showDialog(context: context, child: alert);
}
Inside
MemberState
‘sbuild()
, add a RaisedButton that calls_showOKScreen()
as another child of theColumn
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(member.login),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(children: [
Image.network(member.avatarUrl),
IconButton(
icon: Icon(Icons.arrow_back, color: Colors.green, size: 48.0),
onPressed: () {
Navigator.pop(context);
}),
// Add this raised button
RaisedButton(
child: Text('PRESS ME'),
onPressed: () {
_showOKScreen(context);
})
])));
}
Creating Custom Transitions
- _pushMember(Member member) {
- Navigator.push(context,
- MaterialPageRoute(builder: (context) => MemberWidget(member)));
- }
+_pushMember(Member member) {
+ // ush a new PageRouteBuilder onto the stack.
+ Navigator.push(
+ context,
+ PageRouteBuilder(
+ opaque: true,
+ // Specify the duration using transitionDuration.
+ transitionDuration: const Duration(milliseconds: 1000),
+ // Create the MemberWidget screen using pageBuilder
+ pageBuilder: (BuildContext context, _, __) {
+ return MemberWidget(member);
+ },
+ // Use the transitionsBuilder to create fade and rotation transitions when showing the new route.
+ transitionsBuilder:
+ (_, Animation<double> animation, __, Widget child) {
+ return FadeTransition(
+ opacity: animation,
+ child: RotationTransition(
+ turns: Tween<double>(begin: 0.0, end: 1.0).animate(animation),
+ child: child,
+ ),
+ );
+ }));
+}
+
Where to Go From Here?
Navigation and Routing in the Flutter docs.
The Navigator API docs.
Last updated
Was this helpful?