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
相关产品推荐
相关产品推荐

