詳解flutter如何實(shí)現(xiàn)局部導(dǎo)航管理
引言
今天,小編給大家分享如何在 flutter 中實(shí)現(xiàn) ‘局部導(dǎo)航’。開始之前我們先來統(tǒng)一一下關(guān)于 局部導(dǎo)航 的概念。
局部導(dǎo)航是什么?
我們?cè)?flutter 中使用 navigator 來管理 app 的頁(yè)面堆棧,主要包括 push、pop 這兩種操作。而當(dāng)我們UI設(shè)計(jì)劃分得更細(xì)致時(shí),可能遇到需要在某個(gè)獨(dú)立頁(yè)面里,單獨(dú)維護(hù)一套子級(jí)的堆棧管理。這就叫 局部導(dǎo)航管理。
局部控件內(nèi)單獨(dú)維護(hù)局部范圍內(nèi)的堆棧管理的形式有很多,例如:
- 形式一: 左側(cè)是菜單欄,右側(cè)是內(nèi)容塊,在內(nèi)容塊中單獨(dú)維護(hù)局部的頁(yè)面push、pop、操作。
- 形式二:dialog 彈窗中單獨(dú)維護(hù)布局堆棧管理。
那么下面,小編使用 dialog 的形式來分享實(shí)現(xiàn)過程。

實(shí)現(xiàn)步驟
第一步
創(chuàng)建工具類,用于局部導(dǎo)航管理,思想是:將需要單獨(dú)進(jìn)行堆棧管理的頁(yè)面使用新的子級(jí) navigator 進(jìn)行包裹,單獨(dú)維護(hù)一個(gè) navigator,做到每個(gè)堆棧容器實(shí)現(xiàn)內(nèi)部各自管理。
///工具類:用于局部導(dǎo)航管理
class LocalNavigator extends StatelessWidget {
final Widget child;
const LocalNavigator(this.child, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Navigator(
initialRoute: '/',
onGenerateRoute: (settings) {
return MaterialPageRoute(
settings: const RouteSettings(name: '/'),
builder: (context) {
return child;
},
);
},
);
}
}
第二步
如上 demo 示例,實(shí)現(xiàn)一個(gè)單獨(dú)堆棧管理的彈窗內(nèi)部,對(duì)彈窗方法進(jìn)行封裝處理。
在 showDialog 時(shí)使用我們封裝的工具類 LocalNavigator 作為父節(jié)點(diǎn),對(duì)具體子頁(yè)面節(jié)點(diǎn)進(jìn)行包裹。
那么子頁(yè)面內(nèi)的堆棧操作(push 、pop、)都會(huì)在我們的 LocalNavigator 堆棧中響應(yīng)。
/// 通過局部導(dǎo)航開啟一個(gè)彈窗
static Future<T?> showLocalDialog<T>(
BuildContext context,
Widget child,
) {
return showDialog<T?>(
context: context,
builder: (context) {
return Dialog(
child: SizedBox(
width: 200,
height: 300,
child: LocalNavigator(child),
),
);
},
);
}
第三步
彈出 dialog,附上 demo 樣例的完整代碼
void main() {
runApp(const Material(
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('demo'),
),
body: StatefulBuilder(
builder: (context, setState) {
return Center(
child: TextButton(
child: const Text('打開彈窗'),
onPressed: () {
showLocalDialog<String?>(context, const _PageA())
.then(
(data) {
//接收來自 dialog 的回調(diào)數(shù)據(jù)
if (data != null) {
Fluttertoast.showToast(msg: 'mainPage 接收數(shù)據(jù):$data');
}
},
);
},
),
);
},
),
),
);
}
}
class _PageA extends StatelessWidget {
const _PageA({Key? key}) : super(key: key);
void jumpPageB(BuildContext context) {
Navigator.push<String?>(
context,
MaterialPageRoute(
builder: (context) => const _PageB(),
),
).then(
(data) {
if (data != null) {
//接收來自 pageB 的回調(diào)數(shù)據(jù)
Fluttertoast.showToast(msg: 'pageA 接收數(shù)據(jù):$data');
}
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('PageA')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () {
jumpPageB(context);
},
child: const Text('跳轉(zhuǎn)頁(yè)面B'),
),
],
),
),
);
}
}
class _PageB extends StatelessWidget {
const _PageB({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('PageB')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () {
Navigator.of(context).pop('我是來自pageB的數(shù)據(jù)');
},
child: const Text('返回pageA'),
),
const SizedBox(height: 20),
TextButton(
onPressed: () {
Navigator.of(context, rootNavigator: true).pop('我是來自pageC的數(shù)據(jù)');
},
child: const Text('關(guān)閉整個(gè)彈窗'),
),
],
),
),
);
}
}
技術(shù)點(diǎn)分析:
1. 局部 Navigator 管理重點(diǎn)
將 需要維護(hù)局部堆棧關(guān)系的子節(jié)點(diǎn) 進(jìn)行嵌套,使用自定義的工具類 LocalNavigator 作為父節(jié)點(diǎn)。
2. 返回上一級(jí)頁(yè)面,與關(guān)閉整個(gè)彈窗怎么區(qū)分?
關(guān)鍵點(diǎn)在于 Navigator.of(context) 中的 rootNavigator 可選入?yún)?,默認(rèn)是不使用根節(jié)點(diǎn)下的 navigator。
- 返回上一級(jí)頁(yè)面,使用當(dāng)前的堆棧進(jìn)行操作
Navigator.of(context).pop() - 關(guān)閉整個(gè)彈窗,意味著在根堆棧進(jìn)行 pop 操作
Navigator.of(context, rootNavigator: true).pop()
3. 如何接收頁(yè)面關(guān)閉時(shí)回傳的數(shù)據(jù)?
- 關(guān)閉時(shí)通過 pop() 方法進(jìn)行數(shù)據(jù)回傳
Navigator.of(context).pop(data) - 接收回傳數(shù)據(jù),在打開新堆棧的 push 方法中接收回返回值
Navigator.push<T?>(context, route).then((T){ })T 為返回值的泛型標(biāo)識(shí),注意在接收處理的地方需要對(duì)返回值進(jìn)行判空操作
Navigator.push<String?>(
context,
MaterialPageRoute(
builder: (context) => const _PageB(),
),
).then(
(data) {
if (data != null) {
//接收來自 pageB 的回調(diào)數(shù)據(jù)
Fluttertoast.showToast(msg: 'pageA 接收數(shù)據(jù):$data');
}
},
);以上就是詳解flutter如何實(shí)現(xiàn)局部導(dǎo)航管理的詳細(xì)內(nèi)容,更多關(guān)于flutter局部導(dǎo)航管理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android 使用Retrofit 以純二進(jìn)制文件流上傳文件的操作代碼
文章介紹了如何在Android項(xiàng)目中使用Retrofit通過純二進(jìn)制文件流上傳文件,包括單個(gè)文件流上傳和大文件分段上傳的方法,并詳細(xì)描述了需求協(xié)議、接口定義、RequestInterceptor的使用以及相關(guān)庫(kù)的調(diào)用,感興趣的朋友跟隨小編一起看看吧2024-11-11
Android實(shí)戰(zhàn)教程第九篇之短信高效備份
這篇文章主要為大家詳細(xì)介紹了Android實(shí)戰(zhàn)教程第九篇之短信高效備份,利用xml序列化器備份短信,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
Android圖片加載利器之Picasso擴(kuò)展功能
這篇文章主要為大家詳細(xì)介紹了Android圖片加載利器之Picasso擴(kuò)展功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
android studio 新手入門教程(二)項(xiàng)目的導(dǎo)入教程圖解
這篇文章主要介紹了android studio 新手入門教程(二)項(xiàng)目的導(dǎo)入教程圖解,需要的朋友可以參考下2017-12-12
Android 6.0動(dòng)態(tài)權(quán)限及跳轉(zhuǎn)GPS設(shè)置界面的方法
今天小編就為大家分享一篇Android 6.0動(dòng)態(tài)權(quán)限及跳轉(zhuǎn)GPS設(shè)置界面的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07
Android播放assets文件里視頻文件相關(guān)問題分析
這篇文章主要介紹了Android播放assets文件里視頻文件相關(guān)問題分析,結(jié)合Android播放assets文件出現(xiàn)錯(cuò)誤的實(shí)際問題給出了原因分析與解決方法參考,需要的朋友可以參考下2016-08-08
Android DatePicker和DatePickerDialog基本用法示例
這篇文章主要介紹了Android DatePicker和DatePickerDialog基本用法,實(shí)例分析了DatePicker和DatePickerDialog控件針對(duì)手機(jī)時(shí)間設(shè)置的相關(guān)技巧,需要的朋友可以參考下2016-06-06

