咨询Flutter中实现分段控件(Segment)的可行性及自定义方案
当然可以实现!这种类似原生Segment的切换控件在Flutter里有不少靠谱的实现方式,我给你分享两个实用的方案,都能轻松实现点击按钮切换对应Widget的需求:
方案一:用Flutter自带的
CupertinoSegmentedControl(iOS原生风格) 如果你想要iOS原生风格的分段控件,直接用Flutter提供的CupertinoSegmentedControl就好,它自带选中状态切换和样式,不用自己造轮子:
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class SegmentDemo extends StatefulWidget { const SegmentDemo({super.key}); @override State<SegmentDemo> createState() => _SegmentDemoState(); } class _SegmentDemoState extends State<SegmentDemo> { // 记录当前选中的分段索引 int _selectedSegment = 0; // 对应两个分段的Widget final List<Widget> _pages = const [ Center(child: Text("第一个页面内容")), Center(child: Text("第二个页面内容")), ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("分段控件示例")), body: Column( children: [ // 分段控件 Padding( padding: const EdgeInsets.all(16.0), child: CupertinoSegmentedControl<int>( children: const { 0: Text("按钮1"), 1: Text("按钮2"), }, groupValue: _selectedSegment, onValueChanged: (int value) { setState(() { _selectedSegment = value; }); }, ), ), // 显示对应内容 Expanded(child: _pages[_selectedSegment]), ], ), ); } }
方案二:自定义Material风格分段控件
如果想要Material风格或者更个性化的样式(比如自定义圆角、颜色、边框),可以自己用Row+InkWell来实现,灵活性更高:
import 'package:flutter/material.dart'; class CustomSegmentDemo extends StatefulWidget { const CustomSegmentDemo({super.key}); @override State<CustomSegmentDemo> createState() => _CustomSegmentDemoState(); } class _CustomSegmentDemoState extends State<CustomSegmentDemo> { int _selectedIndex = 0; final List<Widget> _contentWidgets = const [ Center(child: Text("自定义控件-页面1")), Center(child: Text("自定义控件-页面2")), ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("自定义分段控件")), body: Column( children: [ // 自定义分段按钮栏 Padding( padding: const EdgeInsets.all(16.0), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: Colors.grey.shade200, ), child: Row( children: [ Expanded( child: InkWell( onTap: () => setState(() => _selectedIndex = 0), borderRadius: const BorderRadius.horizontal(left: Radius.circular(8)), child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( borderRadius: const BorderRadius.horizontal(left: Radius.circular(8)), color: _selectedIndex == 0 ? Colors.blue : Colors.transparent, ), child: Text( "按钮A", textAlign: TextAlign.center, style: TextStyle( color: _selectedIndex == 0 ? Colors.white : Colors.black, fontWeight: FontWeight.bold, ), ), ), ), ), Expanded( child: InkWell( onTap: () => setState(() => _selectedIndex = 1), borderRadius: const BorderRadius.horizontal(right: Radius.circular(8)), child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( borderRadius: const BorderRadius.horizontal(right: Radius.circular(8)), color: _selectedIndex == 1 ? Colors.blue : Colors.transparent, ), child: Text( "按钮B", textAlign: TextAlign.center, style: TextStyle( color: _selectedIndex == 1 ? Colors.white : Colors.black, fontWeight: FontWeight.bold, ), ), ), ), ), ], ), ), ), // 切换显示的内容 Expanded(child: _contentWidgets[_selectedIndex]), ], ), ); } }
额外小技巧
如果想要切换Widget时有过渡动画,可以把显示内容的部分换成AnimatedSwitcher,比如:
Expanded( child: AnimatedSwitcher( duration: const Duration(milliseconds: 300), child: _contentWidgets[_selectedIndex], ), )
这样切换的时候会有平滑的过渡效果,体验更好~
内容的提问来源于stack exchange,提问作者Praveen Kumar
相关产品推荐
相关产品推荐

