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

Flutter SegmentedButton选中按钮时宽度异常变化问题咨询

Flutter SegmentedButton 选中首尾按钮时宽度变化的原因

在Flutter 3.10.2稳定版中,使用支持多选和空选中的SegmentedButton时,当未选中任何按钮时点击最左侧或最右侧按钮,组件宽度会发生变化,此问题基于官方示例复现。

版本信息

  • Flutter:3.10.2(稳定通道)
  • Dart:3.0.2

复现代码

import 'package:flutter/material.dart';

void main() {
  runApp(const SegmentedButtonApp());
}

class SegmentedButtonApp extends StatelessWidget {
  const SegmentedButtonApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: const <Widget>[
              Spacer(),
              Text('Multiple choice'),
              MultipleChoice(),
              Spacer(),
            ],
          ),
        ),
      ),
    );
  }
}

enum Sizes { extraSmall, small, medium, large, extraLarge }

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

  @override
  State<MultipleChoice> createState() => _MultipleChoiceState();
}

class _MultipleChoiceState extends State<MultipleChoice> {
  Set<Sizes> selection = <Sizes>{};

  @override
  Widget build(BuildContext context) {
    return SegmentedButton<Sizes>(
      segments: const <ButtonSegment<Sizes>>[
        ButtonSegment<Sizes>(value: Sizes.extraSmall, label: Text('XS (Click me)')),
        ButtonSegment<Sizes>(value: Sizes.small, label: Text('S')),
        ButtonSegment<Sizes>(value: Sizes.medium, label: Text('M')),
        ButtonSegment<Sizes>(value: Sizes.large, label: Text('L')),
        ButtonSegment<Sizes>(value: Sizes.extraLarge, label: Text('XL (Click me)')),
      ],
      selected: selection,
      onSelectionChanged: (Set<Sizes> newSelection) {
        setState(() {
          selection = newSelection;
        });
      },
      multiSelectionEnabled: true,
      emptySelectionAllowed: true,
    );
  }
}

宽度变化的原因

这个宽度波动的核心原因是SegmentedButton在空选中状态和单选中状态下的边框渲染逻辑差异:

  • 当没有任何按钮被选中时,整个SegmentedButton的外侧边框采用统一的圆角样式(左右两端都是圆角),此时组件的整体宽度是所有按钮内容宽度加上全局圆角边框的总宽度。
  • 当点击首尾按钮使其被选中时,选中的按钮会单独应用圆角样式(比如最左侧按钮选中时,仅左边缘保留圆角,右侧与相邻按钮衔接处变为直角);未选中的按钮则会调整边框为直角,以贴合选中按钮的样式。这种边框样式的切换会导致布局计算的细微变化——空选中时外侧圆角占用的空间,在选中单个首尾按钮时被转化为按钮内部的直角衔接,最终让组件整体宽度出现肉眼可见的变化。

另外,SegmentedButton的布局是基于内部按钮的内容和边框动态计算的,当边框约束从全局圆角切换到局部圆角时,布局的测量值会发生改变,这也是引发宽度波动的直接因素。

内容的提问来源于stack exchange,提问作者Dark Purple Knight

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 08:50:15