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

如何在Flutter中实现双选项滑动切换组件?求组件名称及实现方法

组件名称及Flutter实现方案

一、组件名称

这个组件叫做分段切换器(Segmented Control),最初是iOS系统的原生组件,后来被广泛应用于多平台APP设计中。它的核心逻辑是提供一组互斥的选项,通过滑动的高亮容器标识当前选中项,和你描述的设计完全匹配。

二、Flutter实现方案

下面提供两种实现方式,一种是用官方组件快速落地,另一种是自定义实现满足个性化样式需求。

1. 官方Cupertino组件快速实现

Flutter的cupertino库自带CupertinoSegmentedControl,原生支持滑动选中效果,代码示例:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class SegmentedControlDemo extends StatefulWidget {
  const SegmentedControlDemo({super.key});

  @override
  State<SegmentedControlDemo> createState() => _SegmentedControlDemoState();
}

class _SegmentedControlDemoState extends State<SegmentedControlDemo> {
  int _selectedIndex = 0;
  final Map<int, Widget> _segments = {
    0: const Text('Option 1'),
    1: const Text('Option 2'),
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CupertinoSegmentedControl(
          children: _segments,
          groupValue: _selectedIndex,
          onValueChanged: (int value) {
            setState(() {
              _selectedIndex = value;
            });
          },
          selectedColor: Colors.blue,
          unselectedColor: Colors.grey.shade200,
          borderColor: Colors.blue,
        ),
      ),
    );
  }
}

该组件会自动处理选中块的滑动动画,样式可通过参数直接调整。

2. 自定义实现个性化样式

如果需要完全控制选中块形状、动画速度等细节,可通过Stack+AnimatedPositioned实现,代码示例:

import 'package:flutter/material.dart';

class CustomSegmentedControl extends StatefulWidget {
  final List<String> options;
  final ValueChanged<int> onSelected;
  final Color selectedBgColor;
  final Color unselectedTextColor;
  final Color selectedTextColor;

  const CustomSegmentedControl({
    super.key,
    required this.options,
    required this.onSelected,
    this.selectedBgColor = Colors.blue,
    this.unselectedTextColor = Colors.black54,
    this.selectedTextColor = Colors.white,
  });

  @override
  State<CustomSegmentedControl> createState() => _CustomSegmentedControlState();
}

class _CustomSegmentedControlState extends State<CustomSegmentedControl> {
  int _selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    final double itemWidth = (MediaQuery.of(context).size.width - 20) / widget.options.length;

    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 10),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(8),
        color: Colors.grey.shade200,
      ),
      child: Stack(
        children: [
          // 滑动选中背景块
          AnimatedPositioned(
            duration: const Duration(milliseconds: 300),
            curve: Curves.easeInOut,
            left: _selectedIndex * itemWidth,
            top: 0,
            bottom: 0,
            width: itemWidth,
            child: Container(
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(8),
                color: widget.selectedBgColor,
              ),
            ),
          ),
          // 选项文本区域
          Row(
            children: List.generate(widget.options.length, (index) {
              return GestureDetector(
                onTap: () {
                  setState(() {
                    _selectedIndex = index;
                  });
                  widget.onSelected(index);
                },
                child: Container(
                  width: itemWidth,
                  padding: const EdgeInsets.symmetric(vertical: 12),
                  alignment: Alignment.center,
                  child: Text(
                    widget.options[index],
                    style: TextStyle(
                      color: _selectedIndex == index
                          ? widget.selectedTextColor
                          : widget.unselectedTextColor,
                      fontWeight: FontWeight.w500,
                    ),
                  ),
                ),
              );
            }),
          ),
        ],
      ),
    );
  }
}

// 使用示例
class CustomSegmentDemo extends StatelessWidget {
  const CustomSegmentDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CustomSegmentedControl(
          options: const ['Option 1', 'Option 2'],
          onSelected: (index) {
            print('选中了选项${index+1}');
          },
        ),
      ),
    );
  }
}

这种方式可以自由定制组件的圆角、动画曲线、文字样式等细节。

内容的提问来源于stack exchange,提问作者Cidiko Andorem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:23:08