Flutter 路由介绍
Flutter中的路由通俗的讲就是页面跳转。在Flutter中通过Navigator组件管理路由导航。 并提供了管理堆栈的方法。如:Navigator.push和Navigator.pop
Flutter中给我们提供了两种配置路由跳转的方式:
- 基本路由
- 命名路由
Flutter 中的普通路由使用
比如我们现在想从HomePage组件跳转到SearchPage组件。
1丶 需要在HomPage中引入SearchPage.dart
import '../SearchPage.dart';
2丶在HomePage中通过下面方法跳转
Center(
child: ElevatedButton(onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(builder: (context){
return const SearchPage();
})
);
},
child: const Text("跳转到搜索页面")),
)
import 'package:flutter/material.dart';
import 'package:flutter_application_1/search.dart';
import 'package:flutter_application_1/user.dart';
import 'home.dart';
import 'category.dart';
import 'setting.dart';
import 'message.dart';
class TabsPage extends StatefulWidget {
const TabsPage({super.key});
@override
State<TabsPage> createState() => _TabsPageState();
}
class _TabsPageState extends State<TabsPage> with SingleTickerProviderStateMixin {
@override
int _currentIndex = 0;
final List _pageList = [
const HomePage(),
const CategoryPage(),
const MessagePage(),
const SettingPage(),
const UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: (){
print('menu');
},
),
title: const Text('Flutter App'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: (){ // 跳转到搜索页面
print('search');
Navigator.of(context).push(
MaterialPageRoute(builder: (BuildContext context){
return const SearchPage();
})
);
},
),
IconButton(
icon: const Icon(Icons.settings),
onPressed: (){
print('settings');
},
),
],
backgroundColor: Colors.red,
),
body: _pageList[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed, // 如果有4个以上的按钮,必须设置type
fixedColor: Colors.red, // 选中的颜色
//iconSize: 35, // 图标大小
onTap: (int index){
print(index);
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '首页',
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: '分类',
),
BottomNavigationBarItem(
icon: Icon(Icons.message),
label: '消息',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: '设置',
),
// 我的
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: '我的',
),
],
),
floatingActionButton: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white,
),
margin: const EdgeInsets.only(top: 4),
padding: const EdgeInsets.all(4),
child: FloatingActionButton(
onPressed: (){
setState(() {
_currentIndex = 2;
});
},
backgroundColor: _currentIndex == 2 ? Colors.red :Colors.blue,
child: const Icon(Icons.add),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
Flutter 中的普通路由跳转传值
import 'package:flutter/material.dart';
import 'package:flutter_application_1/search.dart';
import 'package:flutter_application_1/user.dart';
import 'form.dart';
import 'home.dart';
import 'category.dart';
import 'setting.dart';
import 'message.dart';
class TabsPage extends StatefulWidget {
const TabsPage({super.key});
@override
State<TabsPage> createState() => _TabsPageState();
}
class _TabsPageState extends State<TabsPage> with SingleTickerProviderStateMixin {
@override
int _currentIndex = 0;
final List _pageList = [
const HomePage(),
const CategoryPage(),
const MessagePage(),
const SettingPage(),
const UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: (){
print('menu');
Navigator.of(context).push(
MaterialPageRoute(builder: (BuildContext context){
return const FormPage(title:'我是表单');
})
);
},
),
title: const Text('Flutter App'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: (){
print('search');
Navigator.of(context).push(
MaterialPageRoute(builder: (BuildContext context){
return const SearchPage();
})
);
},
),
IconButton(
icon: const Icon(Icons.settings),
onPressed: (){
print('settings');
},
),
],
backgroundColor: Colors.red,
),
body: _pageList[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed, // 如果有4个以上的按钮,必须设置type
fixedColor: Colors.red, // 选中的颜色
//iconSize: 35, // 图标大小
onTap: (int index){
print(index);
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '首页',
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: '分类',
),
BottomNavigationBarItem(
icon: Icon(Icons.message),
label: '消息',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: '设置',
),
// 我的
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: '我的',
),
],
),
floatingActionButton: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white,
),
margin: const EdgeInsets.only(top: 4),
padding: const EdgeInsets.all(4),
child: FloatingActionButton(
onPressed: (){
setState(() {
_currentIndex = 2;
});
},
backgroundColor: _currentIndex == 2 ? Colors.red :Colors.blue,
child: const Icon(Icons.add),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
Flutter 中的命名路由
import 'package:flutter/material.dart';
import 'package:flutter_application_1/tabs.dart';
import 'home.dart';
import 'search.dart';
import 'form.dart';
import 'news.dart';
// import 'listData.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
// ignore: use_key_in_widget_constructors
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// home: HomePage(),
// home: const Main(),
initialRoute: '/',
routes: (
{
'/': (context) => const Main(),
'/search': (context) => const SearchPage(),
'/form': (context) => const FormPage(title:'我是表单'),
'/news': (context){
return const NewsPage();
},
}
),
);
}
}
class Main extends StatefulWidget {
const Main({ Key? key }) : super(key: key);
@override
// ignore: library_private_types_in_public_api
_MainState createState() => _MainState();
}
class _MainState extends State<Main> {
@override
Widget build(BuildContext context) {
return const TabsPage();
}
}
import 'package:flutter/material.dart';
import 'package:flutter_application_1/search.dart';
import 'package:flutter_application_1/user.dart';
import 'form.dart';
import 'home.dart';
import 'category.dart';
import 'setting.dart';
import 'message.dart';
class TabsPage extends StatefulWidget {
const TabsPage({super.key});
@override
State<TabsPage> createState() => _TabsPageState();
}
class _TabsPageState extends State<TabsPage> with SingleTickerProviderStateMixin {
@override
int _currentIndex = 0;
final List _pageList = [
const HomePage(),
const CategoryPage(),
const MessagePage(),
const SettingPage(),
const UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: (){
print('menu');
Navigator.of(context).push(
MaterialPageRoute(builder: (BuildContext context){
return const FormPage(title:'我是表单');
})
);
},
),
title: const Text('Flutter App'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: (){
print('search');
// Navigator.of(context).push(
// MaterialPageRoute(builder: (BuildContext context){
// return const SearchPage();
// })
// );
Navigator.of(context).pushNamed('/search'); // 命名路由跳转
},
),
IconButton(
icon: const Icon(Icons.settings),
onPressed: (){
print('settings');
},
),
],
backgroundColor: Colors.red,
),
body: _pageList[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed, // 如果有4个以上的按钮,必须设置type
fixedColor: Colors.red, // 选中的颜色
//iconSize: 35, // 图标大小
onTap: (int index){
print(index);
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '首页',
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: '分类',
),
BottomNavigationBarItem(
icon: Icon(Icons.message),
label: '消息',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: '设置',
),
// 我的
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: '我的',
),
],
),
floatingActionButton: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white,
),
margin: const EdgeInsets.only(top: 4),
padding: const EdgeInsets.all(4),
child: FloatingActionButton(
onPressed: (){
setState(() {
_currentIndex = 2;
});
},
backgroundColor: _currentIndex == 2 ? Colors.red :Colors.blue,
child: const Icon(Icons.add),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
Flutter 中的命名路由传值
1丶在main.dart中配置路由
import 'package:flutter/material.dart';
import 'package:flutter_application_1/tabs.dart';
import 'home.dart';
import 'search.dart';
import 'form.dart';
import 'news.dart';
// import 'listData.dart';
void main() {
runApp( MyApp());
}
class MyApp extends StatelessWidget {
// 配置路由
Map router = {
'/': (context) => const Main(),
'/search': (context) => const SearchPage(),
'/form': (context, {arguments}) => FormPage(arguments: arguments),
'/news': (context){
return const NewsPage();
},
};
// ignore: use_key_in_widget_constructors
MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// home: HomePage(),
// home: const Main(),
initialRoute: '/',
// 配置onGenerateRoute 固定写法
onGenerateRoute: (RouteSettings settings){
final String? name = settings.name;
final Function pageContentBuilder = router[name] as Function;
if(pageContentBuilder != null){
if(settings.arguments != null){
final Route route = MaterialPageRoute(
builder: (context) => pageContentBuilder(context, arguments: settings.arguments),
);
return route;
}else{
final Route route = MaterialPageRoute(
builder: (context) => pageContentBuilder(context),
);
return route;
}
}
return null;
}
);
}
}
class Main extends StatefulWidget {
const Main({ Key? key }) : super(key: key);
@override
// ignore: library_private_types_in_public_api
_MainState createState() => _MainState();
}
class _MainState extends State<Main> {
@override
Widget build(BuildContext context) {
return const TabsPage();
}
}
2丶在form.dart中接收参数
import 'package:flutter/material.dart';
class FormPage extends StatefulWidget {
final Map arguments;
const FormPage({super.key, required this.arguments,});
@override
State<FormPage> createState() => _FormPageState();
}
class _FormPageState extends State<FormPage> {
@override
void initState() {
// TODO: implement initState
super.initState();
print(widget.arguments);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.arguments['title']),
),
body: const Center(
child: Text('表单'),
),
);;
}
}
3丶在home.dart中跳转传值
import 'package:flutter/material.dart';
import 'package:flutter_application_1/search.dart';
import 'package:flutter_application_1/user.dart';
import 'form.dart';
import 'home.dart';
import 'category.dart';
import 'setting.dart';
import 'message.dart';
class TabsPage extends StatefulWidget {
const TabsPage({super.key});
@override
State<TabsPage> createState() => _TabsPageState();
}
class _TabsPageState extends State<TabsPage> with SingleTickerProviderStateMixin {
@override
int _currentIndex = 0;
final List _pageList = [
const HomePage(),
const CategoryPage(),
const MessagePage(),
const SettingPage(),
const UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: (){
print('menu');
Navigator.pushNamed(context, '/form',arguments: {
'title':'我是表单'
}); // 命名路由传参跳转
},
),
title: const Text('Flutter App'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: (){
print('search');
// Navigator.of(context).push(
// MaterialPageRoute(builder: (BuildContext context){
// return const SearchPage();
// })
// );
Navigator.of(context).pushNamed('/search');
},
),
IconButton(
icon: const Icon(Icons.settings),
onPressed: (){
print('settings');
},
),
],
backgroundColor: Colors.red,
),
body: _pageList[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed, // 如果有4个以上的按钮,必须设置type
fixedColor: Colors.red, // 选中的颜色
//iconSize: 35, // 图标大小
onTap: (int index){
print(index);
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '首页',
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: '分类',
),
BottomNavigationBarItem(
icon: Icon(Icons.message),
label: '消息',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: '设置',
),
// 我的
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: '我的',
),
],
),
floatingActionButton: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white,
),
margin: const EdgeInsets.only(top: 4),
padding: const EdgeInsets.all(4),
child: FloatingActionButton(
onPressed: (){
setState(() {
_currentIndex = 2;
});
},
backgroundColor: _currentIndex == 2 ? Colors.red :Colors.blue,
child: const Icon(Icons.add),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
Flutter 中的命名路由单独抽离到一个文件中
1丶新建一个router.dart文件
import 'package:flutter/material.dart';
import '../form.dart';
import '../main.dart';
import '../news.dart';
import '../search.dart';
// 配置路由
Map router = {
'/': (context) => const Main(),
'/search': (context) => const SearchPage(),
'/form': (context, {arguments}) => FormPage(arguments: arguments),
'/news': (context){
return const NewsPage();
},
};
// 配置onGenerateRoute 固定写法
var onGenerateRoute = (RouteSettings settings){
final String? name = settings.name;
final Function pageContentBuilder = router[name] as Function;
if(pageContentBuilder != null){
if(settings.arguments != null){
final Route route = MaterialPageRoute(
builder: (context) => pageContentBuilder(context, arguments: settings.arguments),
);
return route;
}else{
final Route route = MaterialPageRoute(
builder: (context) => pageContentBuilder(context),
);
return route;
}
}
return null;
};
2丶在main.dart中引入router.dart文件
import 'package:flutter/material.dart';
import 'package:flutter_application_1/tabs.dart';
import 'home.dart';
import 'router/routers.dart';
import 'search.dart';
import 'form.dart';
import 'news.dart';
// import 'listData.dart';
void main() {
runApp( const MyApp());
}
class MyApp extends StatelessWidget {
// ignore: use_key_in_widget_constructors
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// home: HomePage(),
// home: const Main(),
initialRoute: '/',
onGenerateRoute: onGenerateRoute,
);
}
}
class Main extends StatefulWidget {
const Main({ Key? key }) : super(key: key);
@override
// ignore: library_private_types_in_public_api
_MainState createState() => _MainState();
}
class _MainState extends State<Main> {
@override
Widget build(BuildContext context) {
return const TabsPage();
}
}
Flutter 返回上一级路由
Navigator.of(context).pop();
Flutter 中替换路由
比如我们从用户中心页面跳转到了registerFirst页面,然后从registerFirst页面通过 pushReplacementNamed跳转到了registerSecond页面。这个时候当我们点击registerSecond的返回 按钮的时候它会直接返回到用户中心。
Navigator.of(context).pushReplacementNamed('/registerSecond');
Flutter 返回到根路由
比如我们从用户中心跳转到registerFirst页面,然后从registerFirst页面跳转到registerSecond页面,然 后从registerSecond跳转到了registerThird页面。这个时候我们想的是registerThird注册成功后返回到 用户中心。 这个时候就用到了返回到根路由的方法。
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (BuildContext context) {
return const Tabs();
}), (route) => false);
Flutter Android 和Ios使用同样风格的路由跳转
Material组件库中提供了一个MaterialPageRoute组件,它可以使用和平台风格一致的路由切换动画, 如在iOS上会左右滑动切换,而在Android上会上下滑动切换 , CupertinoPageRoute是Cupertino组件 库提供的iOS风格的路由切换组件如果在Android上也想使用左右切换风格,可以使用 CupertinoPageRoute。
routers.dart中引入cupertino.dart
import 'package:flutter/cupertino.dart';
MaterialPageRoute改为CupertinoPageRoute
import 'package:flutter/cupertino.dart';
import '../pages/tabs.dart';
import '../pages/shop.dart';
import '../pages/user/login.dart';
import '../pages/user/registerFirst.dart';
import '../pages/user/registerSecond.dart';
import '../pages/user/registerThird.dart';
//1、配置路由
Map routes = {
"/": (contxt) => const Tabs(),
"/login": (contxt) => const LoginPage(),
"/registerFirst": (contxt) => const RegisterFirstPage(),
"/registerSecond": (contxt) => const RegisterSecondPage(),
"/registerThird": (contxt) => const RegisterThirdPage(),
"/shop": (contxt, {arguments}) => ShopPage(arguments: arguments),
};
// 2、配置onGenerateRoute 固定写法 这个方法也相当于一个中间件,这里可以做权限判断
var onGenerateRoute = (RouteSettings settings) {
final String? name = settings.name; // /news 或者 /search
final Function? pageContentBuilder = routes[name]; //
Function = (contxt) { return const NewsPage();};
if (pageContentBuilder != null) {
if (settings.arguments != null) {
final Route route = CupertinoPageRoute(
builder: (context) =>
pageContentBuilder(context, arguments: settings.arguments));
return route;
} else {
final Route route =
CupertinoPageRoute(builder: (context) => pageContentBuilder(context));
return route;
}
}
return null;
};
全局配置主题
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
appBarTheme: const AppBarTheme(
centerTitle: true,
)
),
initialRoute: "/",
onGenerateRoute: onGenerateRoute,
);