Flutter Routing#
Routing is very common in single-page applications in web development, and Flutter has its own routing. However, in the Android system, Route refers to an Activity, while in the iOS system, it refers to a View Controller.
Route management involves using a route stack to perform push and pop operations, pushing and popping routes. Pushing means opening a new page, while popping represents closing a page. In addition to using the route stack, other operations are also needed, such as route interception and route redirection.
Normal Routes and Route Navigation#
- Create a new route named MyText (which can pass parameters)
class MyText extends StatefulWidget {
// Other pages navigate to the Form page for named route parameter passing
final Map arguments;
const MyText({super.key, required this.arguments});
@override
State<MyText> createState() => _MyTextState();
}
class _MyTextState extends State<MyText> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Route"),
),
body: Center(
child: Text(widget.arguments.toString()),
),
);
}
}
- Use this route in any other widget (needs to be imported in advance). Here, ElevatedButton is used for demonstration. After clicking the button, it will navigate to the new route (along with passing parameters).
// imported
ElevatedButton(
onPressed: () {
// Route
// Or Navigator.push, depending on the component
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const MyText(
arguments: {'kano': "kanokano.cn"},
);
},
),
);
},
child: const Text("Search (Route Navigation)"),
),
Creating Named Routes#
Note: Named routes have been marked as not recommended in the new Flutter documentation.
Although named routes can handle deep links, the behavior is always the same and can’t be customized. When a new deep link is received by the platform, Flutter pushes a new onto the Navigator regardless of where the user currently is.
Route
Flutter also doesn’t support the browser forward button for applications using named routes. For these reasons, we don’t recommend using named routes in most applications.
-
Create a new route named MyText (directly using the above MyText).
-
Use the Tabs route in main.dart.
import 'package:flutter/material.dart';
// Normal components
import './mytext.dart';
void main(List<String> args) {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "Test",
theme: ThemeData(
primarySwatch: Colors.red,
),
// 1. Initialize the route
initialRoute: '/text1',
// Directly named route
routes: {
'/text1': (context) => const MyText(),
},
);
}
}
- Route navigation
ElevatedButton(
onPressed: () {
// Route
Navigator.pushNamed(context, '/text1');
},
child: const Text("Basic Route Navigation to text1"),
),
Parameter Passing in Named Routes#
Overall, it consists of these three steps:
- Configure the route
- Initialize the route
- Configure onGenerateRouter
class MyApp extends StatelessWidget {
// Route parameter passing - 1. Configure the route (can be extracted as routes.dart)
Map routes = {
"/": (context) => const Tabs(),
"/news": (context) => const NewsPage(),
"/search": (context) => const NewsPage(),
// With parameters
"/form": (context, {arguments}) {
return FormPage(
arguments: arguments,
);
},
"/shop": (context, {arguments}) {
return ShopPage(arguments: arguments);
}
};
MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "Test",
theme: ThemeData(
primarySwatch: Colors.red,
),
// 2. Initialize the route
initialRoute: '/',
// Route parameter passing - 3. Handle the route (can also be extracted as routes.dart)
// Configure onGenerateRouter (I think this is an interceptor)
onGenerateRoute: (RouteSettings settings) {
print(settings); // Route parameter information
print(settings.arguments); // Passed parameters
print(settings.name); // Route name
final String? name = settings.name;
final Function? pageCoutentBuilder = routes[name];
if (pageCoutentBuilder != null) {
// With parameters
if (settings.arguments != null) {
final Route route = MaterialPageRoute(
builder: (context) =>
pageCoutentBuilder(context, arguments: settings.arguments),
);
return route;
} else {
// Without parameters
final Route route = MaterialPageRoute(
builder: (context) => pageCoutentBuilder(context),
);
return route;
}
}
return null;
},
);
}
}
- Route navigation with parameter passing
ElevatedButton(
onPressed: () {
// Route
Navigator.pushNamed(context, '/form', arguments: {"kano": "kanokano"});
},
child: const Text("Named Route Parameter Passing to form"),
),
Returning to the Previous Route#
Simply use
Navigator.pop(context);
// Or
Navigator.of(context).pop()
Replacing Routes#
When we do not want to go back step by step, we can use the route replacement mode (navigate to a page and destroy the current page).
Navigator.of(context).pushReplacementNamed('/xxx')
// Or
Navigator.pushReplacementNamed(context, '/xxx')
Setting Route Navigation Styles#
The Material component library provides a
MaterialPageRoute
component, which can use platform-consistent route transition animations. For example, on iOS, it will slide left and right, while on Android, it will slide up and down.CupertinoPageRoute
is the iOS-style route transition component provided by the Cupertino component library. If you want to use the left-right transition style on Android, you can useCupertinoPageRoute
.
- Import
import 'package:flutter/cupertino.dart';
- Change
MaterialPageRoute
toCupertinoPageRoute
// import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_application_1/pages/form.dart';
import 'package:flutter_application_1/pages/news.dart';
import 'package:flutter_application_1/pages/tabs/shop.dart';
import '../pages/tabs.dart';
// Route parameter passing - 1. Configure the route (can be extracted as routes.dart)
Map routes = {
"/": (context) => const Tabs(),
"/news": (context) => const NewsPage(),
"/search": (context) => const NewsPage(),
// With parameters
"/form": (context, {arguments}) {
return FormPage(
arguments: arguments,
);
},
"/shop": (context, {arguments}) {
return ShopPage(arguments: arguments);
}
};
var onGenerateRoute = (RouteSettings settings) {
final String? name = settings.name;
final Function? pageCoutentBuilder = routes[name];
if (pageCoutentBuilder != null) {
// With parameters
if (settings.arguments != null) {
final Route route = CupertinoPageRoute(
builder: (context) =>
pageCoutentBuilder(context, arguments: settings.arguments),
);
return route;
} else {
// Without parameters
final Route route = CupertinoPageRoute(
builder: (context) => pageCoutentBuilder(context),
);
return route;
}
}
return null;
};