Flutter书籍阅读页面底部导航栏当前页码高亮问题求助
问题解决:Flutter翻页时同步高亮底部页码
问题描述
想在bottomNavigationBar里实现翻书时自动高亮当前页码,原本打算在ListView.builder的CircleAvatar里用backgroundColor: _page == index ? Colors.blue : Colors.white实现,但_page变量无法正确传递:
- 方案1:启用PageView.builder的
onPageChanged,能拿到页码但页面卡第0页无法滚动 - 方案2:在PageView的
itemBuilder里给_page赋值,打印页码正确,但底部的ListView.builder不会动态更新颜色
错误原因
- 自定义的
_onPageViewChange方法错误添加了@override修饰符,导致方法签名异常,影响PageView正常滚动 - 点击页码时直接赋值
_page = index但未调用setState,无法触发底部导航的UI更新 - 方案2里在
itemBuilder中修改_page属于在build流程中直接修改状态,既不会触发UI更新,还违反Flutter状态管理规则
修复后完整代码
class BookFeeder extends StatefulWidget { const BookFeeder({super.key}); static const String id = 'BookFeeder'; @override State<BookFeeder> createState() => _BookFeederState(); } class _BookFeederState extends State<BookFeeder> { bool _showAppBar = false; bool _showBottomBar = false; int _page = 0; late PageController pageController; // 自定义页面切换回调,移除错误的@override void _onPageViewChange(int index) { setState(() { _page = index; }); print("Current Page: $index"); } @override void initState() { super.initState(); pageController = PageController(); } @override void dispose() { pageController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: _showAppBar ? AppBar( leadingWidth: 120, backgroundColor: const Color(0XFF293D63), leading: IconButton( onPressed: () => Navigator.pop(context), icon: SvgPicture.asset('images/button_goback_clean_svg.svg'), ), centerTitle: true, actions: [ IconButton( iconSize: 45, onPressed: () => Navigator.pushNamed(context, MySettings.id), icon: SvgPicture.asset('images/button_settings_clean_svg.svg'), ), ], ) : null, bottomNavigationBar: _showBottomBar ? BottomAppBar( height: 50, shape: const CircularNotchedRectangle(), color: Colors.white, elevation: 9, child: StreamBuilder( stream: FirebaseFirestore.instance .collection('Books') .doc('FishingMonkey') .collection('Content') .snapshots(), builder: (context, AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } return ListView.builder( scrollDirection: Axis.horizontal, itemCount: snapshot.data!.docs.length, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.fromLTRB(4, 4, 4, 4), child: InkWell( onTap: () { setState(() { _page = index; // 更新状态触发UI刷新 }); pageController.animateToPage( index, duration: const Duration(milliseconds: 300), curve: Curves.easeIn, ); print("Current Page: $_page"); }, child: CircleAvatar( child: Text( "$index", style: const TextStyle(fontSize: 12), ), radius: 10, // 根据当前页码切换背景色实现高亮 backgroundColor: _page == index ? const Color(0XFF293D63) : Colors.blue[100], ), ), ); }, ); }, ), ) : null, body: GestureDetector( onTap: () => setState(() { _showAppBar = !_showAppBar; _showBottomBar = !_showBottomBar; }), child: ScrollConfiguration( behavior: ScrollConfiguration.of(context).copyWith( dragDevices: {PointerDeviceKind.touch, PointerDeviceKind.mouse}, ), child: ScrollEdgeListener( edge: ScrollEdge.end, edgeOffset: 0, continuous: false, debounce: const Duration(milliseconds: 400), dispatch: true, listener: () { print('end reached'); Navigator.pop(context); }, child: ScrollConfiguration( behavior: ScrollConfiguration.of(context).copyWith( dragDevices: {PointerDeviceKind.touch, PointerDeviceKind.mouse}, ), child: StreamBuilder( stream: FirebaseFirestore.instance .collection('Books') .doc('FishingMonkey') .collection('Content') .snapshots(), builder: (context, AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } return PageView.builder( controller: pageController, onPageChanged: _onPageViewChange, // 启用页面切换回调 itemCount: snapshot.data!.docs.length, itemBuilder: (context, index) { return BookContent( snap: snapshot.data!.docs[index].data(), ); }, ); }, ), ), ), ), ), ); } }
关键修复点
- 移除
_onPageViewChange方法的@override修饰符,这是自定义方法无需重写 - 在PageView.builder中启用
onPageChanged: _onPageViewChange,翻页时通过setState更新_page,触发底部导航的UI重建 - 点击底部页码时,先调用
setState更新_page再执行页面跳转,确保高亮立刻生效 - 在CircleAvatar的
backgroundColor中通过_page == index判断,动态切换高亮颜色
内容的提问来源于stack exchange,提问作者Hugo
相关产品推荐
相关产品推荐

