底部导航

使用 LazyLoadIndexedStack 配合 BottomNavigationBar实现程序的导航页

flutter pub add lazy_load_indexed_stack

创建root_page.dart维护导航页

root_page.dart
import 'package:e_book_clone/pges/home/home.dart';
import 'package:flutter/material.dart';
import 'package:lazy_load_indexed_stack/lazy_load_indexed_stack.dart';

class RootPage extends StatefulWidget {
const RootPage({super.key});

@override
State<RootPage> createState() => _RootPageState();
}

class _RootPageState extends State<RootPage> {
int _currentIndex = 0;

@override
Widget build(BuildContext context) {
var bg = Theme.of(context).colorScheme.surface;
return Scaffold(
appBar: AppBar(
elevation: 0,
toolbarHeight: 0,
backgroundColor: bg,
surfaceTintColor: bg,
),
backgroundColor: bg,
bottomNavigationBar: _getBottomNavigator(context),
body: LazyLoadIndexedStack(
index: _currentIndex,
children: const [
HomePage(),
Center(child: Text('1')),
Center(child: Text('2')),
Center(child: Text('3')),
],
),
);
}

Widget _getBottomNavigator(BuildContext context) {
return BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
items: List.generate(
4,
(index) {
return BottomNavigationBarItem(
label: '$index',
icon: const Icon(Icons.abc),
);
},
),
);
}
}

导航页刷新方案

使用全局状态来管理切换的下标,如果在当前页面点击跳转到当前页面的底部导航按钮,代表刷新页面。

状态管理

使用Provider维护底部导航栏页下标,创建bottom_nav_provider.dart文件

bottom_nav_provider.dart
class BottomNavProvider with ChangeNotifier {
int _currentIndex = 0;
Map<int, Function()?> refreshFuncs = {};

int get currentIndex => _currentIndex;

set currentIndex(int currentIndex) {
_currentIndex = currentIndex;
notifyListeners();
}

void refresh(int index) {
refreshFuncs[index]?.call();
}

void setIndex(int index) {
currentIndex = index;
}
}

修改导航页面,监听下标,同时判断是否是二次点击页面,即已经在当前页面时,再次点击导航到当前页面。

代码中用到的底部导航组件

flutter pub add salomon_bottom_bar
import 'package:e_book_clone/json/root_app_json.dart';
import 'package:e_book_clone/pages/douban_read/douban_read_page.dart';
import 'package:e_book_clone/pages/home/home_page.dart';
import 'package:e_book_clone/pages/my_book/my_book_page.dart';
import 'package:e_book_clone/pages/ebook_store/store_page.dart';
import 'package:e_book_clone/pages/bottom_nav_provider.dart';
import 'package:flutter/material.dart';
import 'package:lazy_load_indexed_stack/lazy_load_indexed_stack.dart';
import 'package:provider/provider.dart';
import 'package:salomon_bottom_bar/salomon_bottom_bar.dart';

class RootPage extends StatelessWidget {
const RootPage({super.key});

@override
Widget build(BuildContext context) {
var bg = Theme.of(context).colorScheme.surface;
return Scaffold(
appBar: AppBar(
elevation: 0,
toolbarHeight: 0,
backgroundColor: bg,
surfaceTintColor: bg,
),
backgroundColor: bg,
bottomNavigationBar: _getBottomNavigator(context),
body: LazyLoadIndexedStack(
index: Provider.of<BottomNavProvider>(context).currentIndex,
children: const [
HomePage(pageIndex: 0),
DoubanReadPage(pageIndex: 1),
StorePage(pageIndex: 2),
MyBookPage(pageIndex: 3),
],
),
);
}

Widget _getBottomNavigator(BuildContext context) {
var bottomNavProvider =
Provider.of<BottomNavProvider>(context, listen: false);
return SalomonBottomBar(
currentIndex: Provider.of<BottomNavProvider>(context).currentIndex,
onTap: (index) {
if (bottomNavProvider.currentIndex == index) {
// 两次点击同一个页面,刷新当前页面数据
bottomNavProvider.refresh(index);
} else {
bottomNavProvider.currentIndex = index;
}
},
items: List.generate(
rootAppJson.length,
(index) {
return SalomonBottomBarItem(
selectedColor: Theme.of(context).colorScheme.onSurface,
unselectedColor: Theme.of(context).colorScheme.inversePrimary,
icon: Icon(rootAppJson[index]['icon']),
title: Text(rootAppJson[index]['text']),
);
},
),
);
}
}

初始化刷新方法

当再次点击时,调用了刷新方法,该方法接受一个下标,即页面下标。执行对应页面的刷新方法,所以我们需要在页面初始化时将刷新方法添加到refreshFuncs中。

Map<int, Function()?> refreshFuncs = {};

void refresh(int index) {
refreshFuncs[index]?.call();
}

HomePage为案例,代码如下

home/home_page.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:e_book_clone/pages/home/home_vm.dart';

class HomePage extends StatefulWidget {
final int pageIndex;
const HomePage({super.key, required this.pageIndex});

@override
State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
final HomeViewModel _viewmodel = HomeViewModel();

@override
void initState() {
super.initState();
// 进入页面时,请求一次数据
refreshPage();
// 初始化刷新方法,异步方式
Future.microtask(() {
Provider.of<BottomNavProvider>(context, listen: false)
.refreshFuncs[widget.pageIndex] = refreshPage;
});
}

void refreshPage() {
// 请求数据
_viewmodel.getPageData();
}

@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<HomeViewModel>.value(
value: _viewmodel,
child: Scaffold(
backgroundColor: Theme.of(context).colorScheme.surface,
body: _getBody(),
),
);
}
Widget _getBody() {
return const Center(child: Text('HomePage'));
}
}