You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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不会动态更新颜色

错误原因

  1. 自定义的_onPageViewChange方法错误添加了@override修饰符,导致方法签名异常,影响PageView正常滚动
  2. 点击页码时直接赋值_page = index但未调用setState,无法触发底部导航的UI更新
  3. 方案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(),
                      );
                    },
                  );
                },
              ),
            ),
          ),
        ),
      ),
    );
  }
}

关键修复点

  1. 移除_onPageViewChange方法的@override修饰符,这是自定义方法无需重写
  2. 在PageView.builder中启用onPageChanged: _onPageViewChange,翻页时通过setState更新_page,触发底部导航的UI重建
  3. 点击底部页码时,先调用setState更新_page再执行页面跳转,确保高亮立刻生效
  4. 在CircleAvatar的backgroundColor中通过_page == index判断,动态切换高亮颜色

内容的提问来源于stack exchange,提问作者Hugo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 19:40:03