Flutter中的路由即页面跳转,通过Navigator组件管理路由导航并提供管理堆栈的方法,例如Navigator.push和Navigator.pop。
1 普通路由基本使用
# myflutter(项目名)目录结构如下
# 修改“自定义底部导航”的“实现页面切换”代码
# 新增form.dart、search.dart
- pages/
- tabs/
- user.dart
- home.dart【🖊】
- setting.dart
- category.dart【🖊】
- tabs.dart【🖊】
- form.dart【+】
- search.dart【+】
- main.dart
1-1 tabs.dart
import './tabs/user.dart';
import './tabs/home.dart';
import './tabs/setting.dart';
import './tabs/category.dart';
import 'package:flutter/material.dart';
class Tabs extends StatefulWidget {
const Tabs({Key? key}) : super(key: key);
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex = 0;
final List<Widget> _pages = const [
HomePage(),
CategoryPage(),
SettingPage(),
UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('普通路由基本使用')),
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// 选中的颜色
fixedColor: Colors.red,
// 配置底部菜单大小
iconSize: 40,
// 4个以上菜单需配置此项
type: BottomNavigationBarType.fixed,
// 默认选中分类(第二个)
// currentIndex: 1,
currentIndex: _currentIndex,
onTap: (index) {
// 获取点击的索引值
// print(index);
// 注意调用setState
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.category), label: '分类'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
// 没有type菜单图标会被挤掉
BottomNavigationBarItem(icon: Icon(Icons.people), label: '用户'),
],
),
);
}
}
1-2 form.dart
import 'package:flutter/material.dart';
class FormPage extends StatefulWidget {
const FormPage({Key? key}) : super(key: key);
@override
State<FormPage> createState() => _FormPageState();
}
class _FormPageState extends State<FormPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('表单')),
body: const Center(child: Text('表单页面')),
);
}
}
1-3 home.dart
import '../form.dart';
import '../search.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
// 跳转路由
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
// 首页跳转搜索页面
return const SearchPage();
},
),
);
},
child: const Text('搜索'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 跳转路由
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
// 首页跳转表单页面
return const FormPage();
},
),
);
},
child: const Text('跳转到表单页面'),
),
],
),
);
}
}
1-4 search.dart
import 'package:flutter/material.dart';
class SearchPage extends StatefulWidget {
const SearchPage({Key? key}) : super(key: key);
@override
State<SearchPage> createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('搜索')),
body: const Center(child: Text('搜索页面')),
);
}
}
1-5 category.dart
import '../search.dart';
import 'package:flutter/material.dart';
class CategoryPage extends StatefulWidget {
const CategoryPage({Key? key}) : super(key: key);
@override
State<CategoryPage> createState() => _CategoryPageState();
}
class _CategoryPageState extends State<CategoryPage> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
// 跳转路由
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
// 分类跳转搜索页面
return const SearchPage();
},
),
);
},
child: const Text('搜索'),
),
],
),
);
}
}
2 普通路由跳转传值
# myflutter(项目名)目录结构如下,修改“普通路由基本使用”代码,新增news.dart
- pages/
- tabs/
- user.dart
- home.dart【🖊】
- setting.dart
- category.dart
- tabs.dart【🖊】
- news.dart【+】
- form.dart
- search.dart
- main.dart
2-1 tabs.dart
import './tabs/user.dart';
import './tabs/home.dart';
import './tabs/setting.dart';
import './tabs/category.dart';
import 'package:flutter/material.dart';
class Tabs extends StatefulWidget {
const Tabs({Key? key}) : super(key: key);
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex = 0;
final List<Widget> _pages = const [
HomePage(),
CategoryPage(),
SettingPage(),
UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('普通路由跳转传值')),
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// 选中的颜色
fixedColor: Colors.red,
// 配置底部菜单大小
iconSize: 40,
// 4个以上菜单需配置此项
type: BottomNavigationBarType.fixed,
// 默认选中分类(第二个)
// currentIndex: 1,
currentIndex: _currentIndex,
onTap: (index) {
// 获取点击的索引值
// print(index);
// 注意调用setState
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.category), label: '分类'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
// 没有type菜单图标会被挤掉
BottomNavigationBarItem(icon: Icon(Icons.people), label: '用户'),
],
),
);
}
}
2-2 news.dart
import 'package:flutter/material.dart';
// 新闻页面接收上个页面传来的参数
class NewsPage extends StatefulWidget {
final String title;
final int aid;
const NewsPage({Key? key, this.title = '新闻', required this.aid})
: super(key: key);
@override
State<NewsPage> createState() => _NewsPageState();
}
class _NewsPageState extends State<NewsPage> {
@override
void initState() {
super.initState();
print(widget.aid);
print(widget.title);
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
// 返回到上一页
onPressed: () {
Navigator.pop(context);
},
child: const Icon(Icons.home),
),
// 获取NewsPage里面定义的title
appBar: AppBar(title: Text(widget.title)),
body: const Center(child: Text('新闻页面')),
);
}
}
2-3 home.dart
import '../news.dart';
import '../form.dart';
import '../search.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
// 跳转路由
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
// 首页跳转搜索页面
return const SearchPage();
},
),
);
},
child: const Text('搜索'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 跳转路由
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
// 首页跳转表单页面
return const FormPage();
},
),
);
},
child: const Text('跳转到表单页面'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 跳转路由
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const NewsPage(title: '我是标题', aid: 12);
},
),
);
},
child: const Text('跳转传值'),
),
],
),
);
}
}
3 命名路由基本使用
# myflutter(项目名)目录结构如下,修改“普通路由跳转传值”代码
- pages/
- tabs/
- user.dart
- home.dart【🖊】
- setting.dart
- category.dart【🖊】
- tabs.dart【🖊】
- news.dart【🖊】
- form.dart
- search.dart
- main.dart【🖊】
3-1 tabs.dart
import './tabs/user.dart';
import './tabs/home.dart';
import './tabs/setting.dart';
import './tabs/category.dart';
import 'package:flutter/material.dart';
class Tabs extends StatefulWidget {
const Tabs({Key? key}) : super(key: key);
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex = 0;
final List<Widget> _pages = const [
HomePage(),
CategoryPage(),
SettingPage(),
UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('命名路由基本使用')),
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// 选中的颜色
fixedColor: Colors.red,
// 配置底部菜单大小
iconSize: 40,
// 4个以上菜单需配置此项
type: BottomNavigationBarType.fixed,
// 默认选中分类(第二个)
// currentIndex: 1,
currentIndex: _currentIndex,
onTap: (index) {
// 获取点击的索引值
// print(index);
// 注意调用setState
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.category), label: '分类'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
// 没有type菜单图标会被挤掉
BottomNavigationBarItem(icon: Icon(Icons.people), label: '用户'),
],
),
);
}
}
3-2 main.dart
import './pages/tabs.dart';
import './pages/news.dart';
import './pages/form.dart';
import './pages/search.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
// home: const Tabs(),
// 初始化路由
initialRoute: '/',
// 配置路由
routes: {
'/': (context) => const Tabs(),
'/news': (context) => const NewsPage(),
'/form': (context) => const FormPage(),
'/search': (context) {
return const SearchPage();
},
},
);
}
}
3-3 news.dart
import 'package:flutter/material.dart';
class NewsPage extends StatefulWidget {
const NewsPage({Key? key}) : super(key: key);
@override
State<NewsPage> createState() => _NewsPageState();
}
class _NewsPageState extends State<NewsPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('新闻')),
body: const Center(child: Text('新闻页面')),
);
}
}
3-4 home.dart
import '../search.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
// 跳转路由
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
// 首页跳转搜索页面
return const SearchPage();
},
),
);
},
child: const Text('基本路由跳转,引入组件search.dart'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/news');
},
child: const Text('命令路由跳转,main.dart中配置路由'),
),
],
),
);
}
}
3-5 category.dart
import 'package:flutter/material.dart';
class CategoryPage extends StatefulWidget {
const CategoryPage({Key? key}) : super(key: key);
@override
State<CategoryPage> createState() => _CategoryPageState();
}
class _CategoryPageState extends State<CategoryPage> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/search');
},
child: const Text('命名路由跳转到search'),
),
],
),
);
}
}
4 命名路由传值操作
- 命名路由传值需将路由配置移到外面,首先定义Map类型的routes,调用onGenerateRoute处理。
- 然后在对应的页面进行接收传值,在页面中定义arguments用于传值,最后再跳转页面实现传参。
# myflutter(项目名)目录结构如下,修改“命名路由基本使用”代码,并添加shop.dart文件
- pages/
- tabs/
- user.dart
- home.dart【🖊】
- setting.dart
- category.dart
- tabs.dart【🖊】
- news.dart
- form.dart【🖊】
- shop.dart【+】
- search.dart
- main.dart【🖊】
4-1 tabs.dart
import './tabs/user.dart';
import './tabs/home.dart';
import './tabs/setting.dart';
import './tabs/category.dart';
import 'package:flutter/material.dart';
class Tabs extends StatefulWidget {
const Tabs({Key? key}) : super(key: key);
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex = 0;
final List<Widget> _pages = const [
HomePage(),
CategoryPage(),
SettingPage(),
UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('命名路由传值操作')),
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// 选中的颜色
fixedColor: Colors.red,
// 配置底部菜单大小
iconSize: 40,
// 4个以上菜单需配置此项
type: BottomNavigationBarType.fixed,
// 默认选中分类(第二个)
// currentIndex: 1,
currentIndex: _currentIndex,
onTap: (index) {
// 获取点击的索引值
// print(index);
// 注意调用setState
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.category), label: '分类'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
// 没有type菜单图标会被挤掉
BottomNavigationBarItem(icon: Icon(Icons.people), label: '用户'),
],
),
);
}
}
4-2 shop.dart
import 'package:flutter/material.dart';
class ShopPage extends StatefulWidget {
// 接收命名路由跳转传值
final Map arguments;
const ShopPage({Key? key, required this.arguments}) : super(key: key);
@override
State<ShopPage> createState() => _ShopPageState();
}
class _ShopPageState extends State<ShopPage> {
@override
void initState() {
super.initState();
print(widget.arguments);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('商店')),
body: const Center(child: Text('商店页面')),
);
}
}
4-3 form.dart
import 'package:flutter/material.dart';
// 其他页面跳转到form页面
class FormPage extends StatefulWidget {
// 进行命名路由传值
final Map arguments;
const FormPage({Key? key, required this.arguments}) : super(key: key);
@override
State<FormPage> createState() => _FormPageState();
}
class _FormPageState extends State<FormPage> {
@override
void initState() {
super.initState();
// 打印输出
print(widget.arguments);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('表单')),
body: const Center(child: Text('表单页面')),
);
}
}
4-4 main.dart
import './pages/tabs.dart';
import './pages/news.dart';
import './pages/form.dart';
import './pages/shop.dart';
import './pages/search.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// 定义一个Map类型的路由
Map routes = {
'/': (context) => const Tabs(),
'/news': (context) => const NewsPage(),
'/form': (context, {arguments}) => FormPage(arguments: arguments),
'/shop': (context, {arguments}) {
return ShopPage(arguments: arguments);
},
'/search': (context) {
return const SearchPage();
},
};
MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
// home: const Tabs(),
// 初始化路由
initialRoute: '/',
// 固定写法,配置onGenerateRoute
onGenerateRoute: (RouteSettings settings) {
print(settings);
// “/news”或“/search”
print(settings.name);
print(settings.arguments);
// 统一处理
final String? name = settings.name;
final Function? pageContentBuilder = routes[name];
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;
},
);
}
}
4-5 home.dart
import '../search.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
// 跳转路由
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
// 首页跳转搜索页面
return const SearchPage();
},
),
);
},
child: const Text('基本路由跳转,引入组件search.dart'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/news');
},
child: const Text('命令路由跳转,main.dart中配置路由'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(
context,
'/form',
arguments: {'title': '命名路由传值', 'aid': 20},
);
},
child: const Text('命令路由传值操作,跳转到form页面'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(
context,
'/shop',
arguments: {'title': '命名路由传值', 'aid': 30},
);
},
child: const Text('命令路由传值操作,跳转到shop页面'),
),
],
),
);
}
}
5 命名路由代码抽离
# myflutter(项目名)目录结构如下,修改“命名路由传值操作”代码,新增routes.dart
- pages/
- tabs/
- user.dart
- home.dart
- setting.dart
- category.dart
- tabs.dart【🖊】
- news.dart
- form.dart
- shop.dart
- search.dart
- routes
- routes.dart【+】
- main.dart【🖊】
5-1 tabs.dart
import './tabs/user.dart';
import './tabs/home.dart';
import './tabs/setting.dart';
import './tabs/category.dart';
import 'package:flutter/material.dart';
class Tabs extends StatefulWidget {
const Tabs({Key? key}) : super(key: key);
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex = 0;
final List<Widget> _pages = const [
HomePage(),
CategoryPage(),
SettingPage(),
UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('命名路由代码抽离')),
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// 选中的颜色
fixedColor: Colors.red,
// 配置底部菜单大小
iconSize: 40,
// 4个以上菜单需配置此项
type: BottomNavigationBarType.fixed,
// 默认选中分类(第二个)
// currentIndex: 1,
currentIndex: _currentIndex,
onTap: (index) {
// 获取点击的索引值
// print(index);
// 注意调用setState
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.category), label: '分类'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
// 没有type菜单图标会被挤掉
BottomNavigationBarItem(icon: Icon(Icons.people), label: '用户'),
],
),
);
}
}
5-2 main.dart
import './routes/routes.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
// home: const Tabs(),
// 初始化路由
initialRoute: '/',
// 固定写法,配置onGenerateRoute
onGenerateRoute: onGenerateRoute,
);
}
}
5-3 routes.dart
import '../pages/tabs.dart';
import '../pages/news.dart';
import '../pages/form.dart';
import '../pages/shop.dart';
import '../pages/search.dart';
import 'package:flutter/material.dart';
// 定义一个Map类型的路由
Map routes = {
'/': (context) => const Tabs(),
'/news': (context) => const NewsPage(),
'/form': (context, {arguments}) => FormPage(arguments: arguments),
'/shop': (context, {arguments}) {
return ShopPage(arguments: arguments);
},
'/search': (context) {
return const SearchPage();
},
};
// 配置onGenerateRoute,固定写法,该方法相当于一个中间件,可以做权限判断
// ignore: prefer_function_declarations_over_variables
var onGenerateRoute = (RouteSettings settings) {
print(settings);
// “/news”或“/search”
print(settings.name);
print(settings.arguments);
// 统一处理
final String? name = settings.name;
final Function? pageContentBuilder = routes[name];
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;
};
6 返回到上一级路由
# myflutter(项目名)目录结构如下
- pages/
- tabs/
- user.dart
- home.dart
- setting.dart
- category.dart
- user/
- login.dart
- tabs.dart
- routes
- routes.dart
- main.dart
6-1 tabs.dart
import './tabs/user.dart';
import './tabs/home.dart';
import './tabs/setting.dart';
import './tabs/category.dart';
import 'package:flutter/material.dart';
class Tabs extends StatefulWidget {
const Tabs({Key? key}) : super(key: key);
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex = 0;
final List<Widget> _pages = const [
HomePage(),
CategoryPage(),
SettingPage(),
UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('返回到上一级路由')),
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// 选中的颜色
fixedColor: Colors.red,
// 配置底部菜单大小
iconSize: 40,
// 4个以上菜单需配置此项
type: BottomNavigationBarType.fixed,
// 默认选中分类(第二个)
// currentIndex: 1,
currentIndex: _currentIndex,
onTap: (index) {
// 获取点击的索引值
// print(index);
// 注意调用setState
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.category), label: '分类'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
// 没有type菜单图标会被挤掉
BottomNavigationBarItem(icon: Icon(Icons.people), label: '用户'),
],
),
);
}
}
6-2 user.dart
import 'package:flutter/material.dart';
class UserPage extends StatefulWidget {
const UserPage({Key? key}) : super(key: key);
@override
State<UserPage> createState() => _UserPageState();
}
class _UserPageState extends State<UserPage> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
print('执行跳转');
Navigator.pushNamed(context, '/login');
},
child: const Text('登录'),
),
const SizedBox(height: 40),
ElevatedButton(onPressed: () {}, child: const Text('注册')),
],
),
);
}
}
6-3 main.dart
import './routes/routes.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
// home: const Tabs(),
// 初始化路由
initialRoute: '/',
// 固定写法,配置onGenerateRoute
onGenerateRoute: onGenerateRoute,
);
}
}
6-4 login.dart
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('登录页面')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('登录跳转演示,执行登录后返回到上一个页面'),
const SizedBox(height: 40),
ElevatedButton(
onPressed: () {
// 返回到上一级页面
Navigator.of(context).pop();
},
child: const Text('执行登录'),
),
],
),
),
);
}
}
6-5 home.dart
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return const Center(child: Text('首页展示'));
}
}
6-6 routes.dart
import '../pages/tabs.dart';
import '../pages/user/login.dart';
import 'package:flutter/material.dart';
// 定义一个Map类型的路由
Map routes = {
'/': (context) => const Tabs(),
'/login': (context) => const LoginPage(),
};
// 配置onGenerateRoute,固定写法,该方法相当于一个中间件,可以做权限判断
// ignore: prefer_function_declarations_over_variables
var onGenerateRoute = (RouteSettings settings) {
// 统一处理
final String? name = settings.name;
final Function? pageContentBuilder = routes[name];
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;
};
6-7 setting.dart
import 'package:flutter/material.dart';
class SettingPage extends StatefulWidget {
const SettingPage({Key? key}) : super(key: key);
@override
State<SettingPage> createState() => _SettingPageState();
}
class _SettingPageState extends State<SettingPage> {
@override
Widget build(BuildContext context) {
return const Center(child: Text('系统设置'));
}
}
6-8 category.dart
import 'package:flutter/material.dart';
class CategoryPage extends StatefulWidget {
const CategoryPage({Key? key}) : super(key: key);
@override
State<CategoryPage> createState() => _CategoryPageState();
}
class _CategoryPageState extends State<CategoryPage> {
@override
Widget build(BuildContext context) {
return const Center(child: Text('分类页面'));
}
}
7 Flutter中替换路由
- 比如:registerFirst > registerSecond > registerThird > registerFirst。
- registerSecond页,通过pushReplacementNamed()跳转到registerThird页。
Navigator.of(context).pushReplacementNamed('/registerSecond');
。- registerThird页,通过点击registerThird的返回按钮,返回registerFirst页。
# myflutter(项目名)目录结构如下,修改“返回到上一级路由”代码
# 新增registerFirst.dart、registerSecond.dart、registerThird.dart
- pages/
- tabs/
- user.dart【🖊】
- home.dart
- setting.dart
- category.dart
- user/
- login.dart
- registerFirst.dart【+】
- registerSecond.dart【+】
- registerThird.dart【+】
- tabs.dart【🖊】
- routes
- routes.dart【🖊】
- main.dart
7-1 tabs.dart
import './tabs/user.dart';
import './tabs/home.dart';
import './tabs/setting.dart';
import './tabs/category.dart';
import 'package:flutter/material.dart';
class Tabs extends StatefulWidget {
const Tabs({Key? key}) : super(key: key);
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex = 0;
final List<Widget> _pages = const [
HomePage(),
CategoryPage(),
SettingPage(),
UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Flutter中替换路由')),
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// 选中的颜色
fixedColor: Colors.red,
// 配置底部菜单大小
iconSize: 40,
// 4个以上菜单需配置此项
type: BottomNavigationBarType.fixed,
// 默认选中分类(第二个)
// currentIndex: 1,
currentIndex: _currentIndex,
onTap: (index) {
// 获取点击的索引值
// print(index);
// 注意调用setState
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.category), label: '分类'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
// 没有type菜单图标会被挤掉
BottomNavigationBarItem(icon: Icon(Icons.people), label: '用户'),
],
),
);
}
}
7-2 user.dart
import 'package:flutter/material.dart';
class UserPage extends StatefulWidget {
const UserPage({Key? key}) : super(key: key);
@override
State<UserPage> createState() => _UserPageState();
}
class _UserPageState extends State<UserPage> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
print('执行跳转');
Navigator.pushNamed(context, '/login');
},
child: const Text('登录'),
),
const SizedBox(height: 40),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/registerFirst');
},
child: const Text('注册'),
),
],
),
);
}
}
7-3 routes.dart
import '../pages/tabs.dart';
import '../pages/user/login.dart';
import 'package:flutter/material.dart';
import '../pages/user/registerThird.dart';
import '../pages/user/registerFirst.dart';
import '../pages/user/registerSecond.dart';
// 定义一个Map类型的路由
Map routes = {
'/': (context) => const Tabs(),
'/login': (context) => const LoginPage(),
'/registerThird': (context) => const RegisterThirdPage(),
'/registerFirst': (context) => const RegisterFirstPage(),
'/registerSecond': (context) => const RegisterSecondPage(),
};
// 配置onGenerateRoute,固定写法,该方法相当于一个中间件,可以做权限判断
// ignore: prefer_function_declarations_over_variables
var onGenerateRoute = (RouteSettings settings) {
// 统一处理
final String? name = settings.name;
final Function? pageContentBuilder = routes[name];
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;
};
7-4 registerFirst.dart
import 'package:flutter/material.dart';
class RegisterFirstPage extends StatefulWidget {
const RegisterFirstPage({Key? key}) : super(key: key);
@override
State<RegisterFirstPage> createState() => _RegisterFirstPageState();
}
class _RegisterFirstPageState extends State<RegisterFirstPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('注册第一步')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('注册第一步'),
const SizedBox(height: 40),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/registerSecond');
},
child: const Text('下一步'),
),
],
),
),
);
}
}
7-5 registerThird.dart
import 'package:flutter/material.dart';
class RegisterThirdPage extends StatefulWidget {
const RegisterThirdPage({Key? key}) : super(key: key);
@override
State<RegisterThirdPage> createState() => _RegisterThirdPageState();
}
class _RegisterThirdPageState extends State<RegisterThirdPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('注册第三步')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('注册第三步'),
const SizedBox(height: 40),
ElevatedButton(onPressed: () {}, child: const Text('完成注册')),
],
),
),
);
}
}
7-6 registerSecond.dart
import 'package:flutter/material.dart';
class RegisterSecondPage extends StatefulWidget {
const RegisterSecondPage({Key? key}) : super(key: key);
@override
State<RegisterSecondPage> createState() => _RegisterSecondPageState();
}
class _RegisterSecondPageState extends State<RegisterSecondPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('注册第二步')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('注册第二步'),
const SizedBox(height: 40),
ElevatedButton(
onPressed: () {
// 命名路由跳转
// Navigator.pushNamed(context, '/registerThird');
// 替换路由跳转
Navigator.of(context).pushReplacementNamed('/registerThird');
},
child: const Text('下一步'),
),
],
),
),
);
}
}
8 返回到根路由方法
- 用户中心 > registerFirst > registerSecond > registerThird > 用户中心。
- registerThird注册成功后返回用户中心,此时需要用返回到根路由的方法。
# myflutter(项目名)目录结构如下,修改“Flutter中替换路由”代码
- pages/
- tabs/
- user.dart
- home.dart
- setting.dart
- category.dart
- user/
- login.dart
- registerFirst.dart
- registerSecond.dart
- registerThird.dart【🖊】
- tabs.dart【🖊】
- routes
- routes.dart
- main.dart【🖊】
8-1 tabs.dart
import './tabs/user.dart';
import './tabs/home.dart';
import './tabs/setting.dart';
import './tabs/category.dart';
import 'package:flutter/material.dart';
class Tabs extends StatefulWidget {
final int index;
const Tabs({Key? key, this.index = 0}) : super(key: key);
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
late int _currentIndex;
@override
void initState() {
super.initState();
_currentIndex = widget.index;
}
final List<Widget> _pages = const [
HomePage(),
CategoryPage(),
SettingPage(),
UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('返回到根路由方法')),
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// 选中的颜色
fixedColor: Colors.red,
// 配置底部菜单大小
iconSize: 40,
// 4个以上菜单需配置此项
type: BottomNavigationBarType.fixed,
// 默认选中分类(第二个)
// currentIndex: 1,
currentIndex: _currentIndex,
onTap: (index) {
// 获取点击的索引值
// print(index);
// 注意调用setState
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.category), label: '分类'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
// 没有type菜单图标会被挤掉
BottomNavigationBarItem(icon: Icon(Icons.people), label: '用户'),
],
),
);
}
}
8-2 main.dart
import './routes/routes.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
// home: const Tabs(),
// 初始化路由,首次运行加载登录页
initialRoute: '/login',
// 固定写法,配置onGenerateRoute
onGenerateRoute: onGenerateRoute,
);
}
}
8-3 registerThird.dart
import '../tabs.dart';
import 'package:flutter/material.dart';
class RegisterThirdPage extends StatefulWidget {
const RegisterThirdPage({Key? key}) : super(key: key);
@override
State<RegisterThirdPage> createState() => _RegisterThirdPageState();
}
class _RegisterThirdPageState extends State<RegisterThirdPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('注册第三步')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('注册第三步'),
const SizedBox(height: 40),
ElevatedButton(
onPressed: () {
// 返回到根页面
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (BuildContext context) {
// index指定返回的页面
return const Tabs(index: 3);
},
),
(route) => false,
);
},
child: const Text('完成注册'),
),
],
),
),
);
}
}
9 同风格的路由跳转
- MaterialPageRoute组件可以使用和平台风格一致的路由切换动画。
- 例如在iOS上会左右滑动切换,而在Android上则会上下滑动切换。
- CupertinoPageRoute是Cupertino组件库提供的iOS风格的路由切换组件。
- 如果在Android上也想使用左右切换风格,可以使用CupertinoPageRoute。
- 在iOS中appBarTheme的标题是自动居中的,而在Android中是自动居左的。
# myflutter(项目名)目录结构如下,修改“返回到根路由方法”代码
- pages/
- tabs/
- user.dart
- home.dart
- setting.dart
- category.dart
- user/
- login.dart
- registerFirst.dart
- registerSecond.dart
- registerThird.dart
- tabs.dart【🖊】
- routes
- routes.dart【🖊】
- main.dart【🖊】
9-1 tabs.dart
import './tabs/user.dart';
import './tabs/home.dart';
import './tabs/setting.dart';
import './tabs/category.dart';
import 'package:flutter/material.dart';
class Tabs extends StatefulWidget {
final int index;
const Tabs({Key? key, this.index = 0}) : super(key: key);
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
late int _currentIndex;
@override
void initState() {
super.initState();
_currentIndex = widget.index;
}
final List<Widget> _pages = const [
HomePage(),
CategoryPage(),
SettingPage(),
UserPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('同风格的路由跳转')),
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// 选中的颜色
fixedColor: Colors.red,
// 配置底部菜单大小
iconSize: 40,
// 4个以上菜单需配置此项
type: BottomNavigationBarType.fixed,
// 默认选中分类(第二个)
// currentIndex: 1,
currentIndex: _currentIndex,
onTap: (index) {
// 获取点击的索引值
// print(index);
// 注意调用setState
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
BottomNavigationBarItem(icon: Icon(Icons.category), label: '分类'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
// 没有type菜单图标会被挤掉
BottomNavigationBarItem(icon: Icon(Icons.people), label: '用户'),
],
),
);
}
}
9-2 main.dart
import './routes/routes.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
// 去掉右上角debug图标
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
// 全局配置主题
appBarTheme: const AppBarTheme(
// 主题标题全部居中显示
centerTitle: true,
),
),
// home: const Tabs(),
// 初始化路由,首次运行加载登录页
initialRoute: '/login',
// 固定写法,配置onGenerateRoute
onGenerateRoute: onGenerateRoute,
);
}
}
9-3 routes.dart
import '../pages/tabs.dart';
import '../pages/user/login.dart';
// 配置iOS风格的路由,引入库
import 'package:flutter/cupertino.dart';
// import 'package:flutter/material.dart';
import '../pages/user/registerThird.dart';
import '../pages/user/registerFirst.dart';
import '../pages/user/registerSecond.dart';
// 定义一个Map类型的路由
Map routes = {
'/': (context) => const Tabs(),
'/login': (context) => const LoginPage(),
'/registerThird': (context) => const RegisterThirdPage(),
'/registerFirst': (context) => const RegisterFirstPage(),
'/registerSecond': (context) => const RegisterSecondPage(),
};
// 配置onGenerateRoute,固定写法,该方法相当于一个中间件,可以做权限判断
// ignore: prefer_function_declarations_over_variables
var onGenerateRoute = (RouteSettings settings) {
// 统一处理
final String? name = settings.name;
final Function? pageContentBuilder = routes[name];
if (pageContentBuilder != null) {
if (settings.arguments != null) {
// final Route route = MaterialPageRoute(
// 替换MaterialPageRoute
final Route route = CupertinoPageRoute(
builder:
(context) =>
pageContentBuilder(context, arguments: settings.arguments),
);
return route;
} else {
// final Route route = MaterialPageRoute(
final Route route = CupertinoPageRoute(
builder: (context) => pageContentBuilder(context),
);
return route;
}
}
return null;
};