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

Flutter实现双页面滑动动画导航指示器

实现Flutter页面导航的平滑滑动滑块指示器

修改思路

将原有的每个标签独立底部边框,替换为单个全局滑块,通过监听PageController的页面偏移量,动态计算滑块的位置,实现跟随页面切换平滑滑动的效果。

完整代码修改

1. 重构导航栏布局(添加滑块容器)

将原有的Row嵌套进Stack,新增滑动滑块组件:

Stack(
  alignment: Alignment.bottomCenter,
  children: [
    Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: [
        pageSelector("Upcoming", selectedPage == 0, 0),
        pageSelector("Previous", selectedPage == 1, 1)
      ],
    ),
    // 跟随页面滑动的指示器滑块
    AnimatedBuilder(
      animation: pageController,
      builder: (context, child) {
        // 获取当前页面的偏移比例(0对应第0页,1对应第1页)
        double pageOffset = pageController.hasClients ? pageController.page ?? 0 : 0;
        // 计算滑块的左偏移:从0到屏幕宽度的一半
        double sliderLeft = pageOffset * MediaQuery.of(context).size.width / 2;
        // 滑块宽度固定为单个标签的宽度(屏幕宽度的1/2)
        double sliderWidth = MediaQuery.of(context).size.width / 2;
        
        return Positioned(
          left: sliderLeft,
          bottom: 0,
          width: sliderWidth,
          height: 2,
          child: Container(
            color: Colpal.main,
          ),
        );
      },
    ),
  ],
),

2. 简化pageSelector组件(移除原有边框逻辑)

删除原有的底部边框装饰,只保留文本样式和点击交互:

Widget pageSelector(String text, bool selected, int number) {
  return Expanded(
    child: GestureDetector(
      onTap: () {
        pageController.animateToPage(
          number,
          duration: const Duration(milliseconds: 300),
          curve: Curves.easeInOut,
        );
        setState(() {
          selectedPage = number;
        });
      },
      child: Padding(
        padding: const EdgeInsets.only(bottom: 8),
        child: Text(
          text,
          textAlign: TextAlign.center,
          style: TextStyle(
            fontSize: 17,
            color: selected ? null : Colpal.grey,
            fontWeight: selected ? FontWeight.w500 : FontWeight.normal,
          ),
        ),
      ),
    ),
  );
}

3. 补充控制器释放(可选但推荐)

在State类的dispose方法中释放PageController,避免内存泄漏:

@override
void dispose() {
  pageController.dispose();
  super.dispose();
}

关键逻辑说明

  • Stack布局:将导航标签和滑块置于同一层级,滑块通过Positioned固定在底部,确保覆盖在标签下方。
  • AnimatedBuilder联动PageController:利用PageController的动画特性,实时获取页面偏移量,动态计算滑块的左偏移值,实现平滑跟随。
  • 自适应宽度计算:针对两个标签的场景,滑块宽度固定为屏幕宽度的1/2,偏移量从0线性过渡到屏幕宽度的1/2,完美匹配页面切换节奏。

内容的提问来源于stack exchange,提问作者swann.wlm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 06:33:23