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

咨询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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:17:57