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

如何在Flutter中自定义Switch组件的Thumb(滑块)尺寸?

Flutter Switch组件Thumb尺寸自定义方案

原生Switch组件没有暴露直接修改Thumb(滑块)尺寸的参数,无法直接调整。你之前尝试的Transform.scale会缩放整个组件,不符合需求,下面提供两种精准修改Thumb尺寸的方案:

方案一:基于原生Switch封装(保留原生轨道样式)

通过Stack包裹原生Switch,隐藏其默认Thumb,然后自定义Thumb并根据开关状态控制位置,既能保留原生轨道的交互和样式,又能单独调整Thumb尺寸。

封装代码

class CustomThumbSwitch extends StatefulWidget {
  final bool value;
  final ValueChanged<bool> onChanged;
  final double thumbSize;

  const CustomThumbSwitch({
    super.key,
    required this.value,
    required this.onChanged,
    this.thumbSize = 24, // 默认和原生Thumb尺寸一致
  });

  @override
  State<CustomThumbSwitch> createState() => _CustomThumbSwitchState();
}

class _CustomThumbSwitchState extends State<CustomThumbSwitch> {
  late bool _currentValue;

  @override
  void initState() {
    super.initState();
    _currentValue = widget.value;
  }

  @override
  void didUpdateWidget(covariant CustomThumbSwitch oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.value != widget.value) {
      _currentValue = widget.value;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.center,
      children: [
        // 原生Switch,隐藏默认Thumb
        Switch(
          value: _currentValue,
          onChanged: (value) {
            setState(() => _currentValue = value);
            widget.onChanged(value);
          },
          thumbColor: MaterialStateProperty.all(Colors.transparent),
          trackColor: MaterialStateProperty.resolveWith((states) {
            if (states.contains(MaterialState.selected)) {
              return Theme.of(context).colorScheme.primary;
            }
            return Colors.grey.shade300;
          }),
          // 可根据需求保留其他原生属性,比如activeTrackColor等
        ),
        // 自定义Thumb
        AnimatedPositioned(
          duration: const Duration(milliseconds: 200),
          // 根据Switch轨道宽度计算位置(原生轨道宽度约48,左右边距4)
          left: _currentValue 
              ? 48 - widget.thumbSize - 4 
              : 4,
          child: Container(
            width: widget.thumbSize,
            height: widget.thumbSize,
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(widget.thumbSize / 2),
              boxShadow: [
                BoxShadow(
                  color: Colors.black.withOpacity(0.2),
                  blurRadius: 2,
                  offset: const Offset(0, 1),
                )
              ],
            ),
          ),
        ),
      ],
    );
  }
}

使用方式

bool isSwitched = false;

// 在build中使用
CustomThumbSwitch(
  value: isSwitched,
  onChanged: (value) {
    setState(() => isSwitched = value);
  },
  thumbSize: 30, // 设置你需要的Thumb尺寸
)

方案二:完全自定义Switch组件(更灵活)

如果需要更极致的控制,直接用GestureDetector和AnimatedContainer实现一个自定义Switch,完全独立于原生组件,可单独调整Thumb、轨道的所有尺寸和样式。

自定义代码

class CustomSwitch extends StatefulWidget {
  final bool value;
  final ValueChanged<bool> onChanged;
  final double thumbSize;
  final double trackHeight;
  final double trackWidth;

  const CustomSwitch({
    super.key,
    required this.value,
    required this.onChanged,
    this.thumbSize = 30,
    this.trackHeight = 18, // 对应原生Switch轨道高度
    this.trackWidth = 48, // 对应原生Switch轨道宽度
  });

  @override
  State<CustomSwitch> createState() => _CustomSwitchState();
}

class _CustomSwitchState extends State<CustomSwitch> {
  late bool _currentValue;

  @override
  void initState() {
    super.initState();
    _currentValue = widget.value;
  }

  @override
  void didUpdateWidget(covariant CustomSwitch oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.value != widget.value) {
      _currentValue = widget.value;
    }
  }

  void _toggleSwitch() {
    final newValue = !_currentValue;
    setState(() => _currentValue = newValue);
    widget.onChanged(newValue);
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _toggleSwitch,
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 200),
        width: widget.trackWidth,
        height: widget.trackHeight,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(widget.trackHeight / 2),
          color: _currentValue
              ? Theme.of(context).colorScheme.primary
              : Colors.grey.shade300,
        ),
        child: AnimatedAlign(
          duration: const Duration(milliseconds: 200),
          alignment: _currentValue 
              ? Alignment.centerRight 
              : Alignment.centerLeft,
          child: Container(
            margin: EdgeInsets.all((widget.trackHeight - widget.thumbSize) / 2),
            width: widget.thumbSize,
            height: widget.thumbSize,
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(widget.thumbSize / 2),
              boxShadow: [
                BoxShadow(
                  color: Colors.black.withOpacity(0.2),
                  blurRadius: 2,
                  offset: const Offset(0, 1),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

使用方式

bool isSwitched = false;

// 在build中使用
CustomSwitch(
  value: isSwitched,
  onChanged: (value) {
    setState(() => isSwitched = value);
  },
  thumbSize: 30, // 自定义Thumb尺寸
  trackHeight: 18, // 保持轨道高度和原生一致,不影响其他外观
)

内容的提问来源于stack exchange,提问作者Dhipin M K

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 10:17:32