如何创建带clipPath边框裁剪的Flutter分段选择控件
分段选择控件优化方案
我想要实现如图所示的分段选择控件:
目前我已经做出了接近的效果,但存在边框间隙和切换时圆角方向异常的问题。以下是我的实现代码:
class SegmentedControl extends Stateful Widget { @override _SegmentedControlState createState() => _SegmentedControlState(); } class _SegmentedControlState extends State<SegmentedControl> { bool isSpendingSelected = true; @override Widget build(BuildContext context) { return Container( width: 300, height: 50, decoration: BoxDecoration( borderRadius: BorderRadius.circular(25), border: Border.all( color: Colors.grey, ), ), child: Stack( children: [ AnimatedPositioned( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, left: isSpendingSelected ? 0 : 150, child: Container( width: 150, height: 50, decoration: BoxDecoration( color: const Color(0xFF22303C), // Dark color for selected tab borderRadius: BorderRadius.circular(25), ), ), ), Row( children: [ Expanded( child: GestureDetector( onTap: () { setState(() { isSpendingSelected = true; }); }, child: Center( child: Text( 'Spending', style: TextStyle( color: isSpendingSelected ? Colors.white : Colors.grey, fontWeight: FontWeight.bold, ), ), ), ), ), Expanded( child: GestureDetector( onTap: () { setState(() { isSpendingSelected = false; }); }, child: Center( child: Text( 'Saving', style: TextStyle( color: isSpendingSelected ? Colors.grey : Colors.grey, fontWeight: FontWeight.bold, ), ), ), ), ), ], ), ], ), ); } }
问题修复方案
针对上述问题,修改后的代码如下:
class SegmentedControl extends Stateful Widget { @override _SegmentedControlState createState() => _SegmentedControlState(); } class _SegmentedControlState extends State<SegmentedControl> { bool isSpendingSelected = true; @override Widget build(BuildContext context) { return Container( width: 300, height: 50, padding: const EdgeInsets.all(2), // 预留边框空间,解决间隙问题 decoration: BoxDecoration( borderRadius: BorderRadius.circular(25), border: Border.all(color: Colors.grey), ), child: Stack( children: [ AnimatedPositioned( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, left: isSpendingSelected ? 0 : 148, // 适配padding后的宽度偏移 child: Container( width: 148, // 300减去左右padding后的均分宽度 height: 46, // 50减去上下padding后的高度 decoration: BoxDecoration( color: const Color(0xFF22303C), // 根据选中状态动态设置圆角,解决方向异常 borderRadius: isSpendingSelected ? const BorderRadius.only( topLeft: Radius.circular(23), bottomLeft: Radius.circular(23), ) : const BorderRadius.only( topRight: Radius.circular(23), bottomRight: Radius.circular(23), ), ), ), ), Row( children: [ Expanded( child: GestureDetector( onTap: () => setState(() => isSpendingSelected = true), child: Center( child: Text( 'Spending', style: TextStyle( color: isSpendingSelected ? Colors.white : Colors.grey, fontWeight: FontWeight.bold, ), ), ), ), ), Expanded( child: GestureDetector( onTap: () => setState(() => isSpendingSelected = false), child: Center( child: Text( 'Saving', style: TextStyle( // 修正选中时的文本颜色 color: isSpendingSelected ? Colors.grey : Colors.white, fontWeight: FontWeight.bold, ), ), ), ), ), ], ), ], ), ); } }
关键修改点说明
- 边框间隙修复:给外部容器添加2px内边距,让选中容器与外部边框保留间隔,避免覆盖边框导致的视觉缝隙。
- 圆角方向修复:根据选中状态仅保留对应侧的圆角,切换时不会出现与外部边框冲突的圆角样式。
- 文本颜色修正:调整"Saving"的文本颜色逻辑,选中时显示白色,与设计图保持一致。
内容的提问来源于stack exchange,提问作者Gbenga B Ayannuga
相关产品推荐
相关产品推荐

