Files
pangolin/client/lib/widgets/seg_switch.dart
T
wangjia ce485a1b62 fix(ui): SegSwitch 用 FittedBox(scaleDown) 防窄容器截断文字
添加规则弹层的动作段选(Direct/Tunnel/Reject)在窄弹层里被 icon+文字挤到 ellipsis 截断
成「Dire…/Tun…/Reje…」。改:段内容包 FittedBox(scaleDown)——放得下原样(宽段选/goldens
不变),放不下整体等比缩放而非截断;padding 16→12 留余量。flutter test 265/265 无 golden 回归。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-29 08:42:27 +08:00

83 lines
2.8 KiB
Dart

// seg_switch.dart — 分段开关(镜像 design/prototype atoms .segswitch)。
// 一排等宽选项,每项 leading 图标 + 文字;选中态 surface 底 + 柔和阴影 + fg1,
// 未选 fg2;容器 bg-subtle + border + full 圆角。渠道/币种/主题等二选一场景通用。
import 'package:flutter/material.dart';
import '../pangolin_theme.dart';
/// 单个分段项:图标 + 文案。
typedef SegOption = ({IconData icon, String label});
class SegSwitch extends StatelessWidget {
const SegSwitch({
super.key,
required this.options,
required this.selectedIndex,
required this.onChanged,
});
final List<SegOption> options;
final int selectedIndex;
final ValueChanged<int> onChanged;
@override
Widget build(BuildContext context) {
final c = context.pangolin;
return Container(
// .segswitch:bg-subtle + border + full 圆角 + space-1 内边距/间隙
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: c.bgSubtle,
border: Border.all(color: c.border),
borderRadius: BorderRadius.circular(PangolinRadius.full),
),
child: Row(
children: [
for (var i = 0; i < options.length; i++) ...[
if (i > 0) const SizedBox(width: 4),
Expanded(child: _opt(c, i, options[i])),
],
],
),
);
}
Widget _opt(PangolinScheme c, int i, SegOption o) {
final active = i == selectedIndex;
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: active ? null : () => onChanged(i),
child: AnimatedContainer(
duration: const Duration(milliseconds: 140),
curve: Curves.easeOut,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
// .segswitch-opt.is-active:surface 底 + shadow-sm;未选透明
color: active ? c.surface : Colors.transparent,
borderRadius: BorderRadius.circular(PangolinRadius.full),
boxShadow: active ? PangolinShadow.sm : null,
),
// FittedBox(scaleDown):放得下则原样(宽段选不变),放不下则图标+文字整体
// 等比缩放而非把文字 ellipsis 截断(窄弹层里 Direct/Tunnel/Reject 曾被截成 Dire…)。
child: FittedBox(
fit: BoxFit.scaleDown,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(o.icon, size: 16, color: active ? c.fg1 : c.fg2),
const SizedBox(width: 8),
Text(
o.label,
maxLines: 1,
style: PangolinText.sm.copyWith(
color: active ? c.fg1 : c.fg2,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
);
}
}