Skip to content

Picker 选择器 ​

声明式底部滚轮选择器。@Binding var visible 控制显隐,@Binding var value 是选中项索引, 滚轮为自绘(DragGesture + 松手吸附),无系统控件依赖。

契约源:lh-ui-core/specs/picker.json · 黄金用例:lh-ui-core/cases/picker.json(8 条,已翻译为 XCTest,macOS 宿主即可运行)

基本形态 ​

底部弹出:顶部工具栏(取消 / 标题 / 确认),中间是滚轮与两条指示线。

9:41Picker 基本
取消选择确认
选项一
选项二
选项三

HTML 模拟预览(iOS / SwiftUI 外观),非真机渲染

swift
@State private var visible = false
@State private var index = 1
let options = ["选项一", "选项二", "选项三"]

LhPicker(
  visible: $visible,
  options: options,
  value: $index,
  title: "选择"
)

滚轮交互 ​

  • 拖动改变整体偏移;松手后吸附到最近候选项(动画时长 motion.duration.base), 选中索引变化时触发 onValueChange(黄金用例 scroll-emits-onvaluechange)。
  • 指示线间距 = picker.itemHeight,选中项恒落在两线正中。

回调与边界 ​

  • 「确认」触发 onConfirm(payload 为当前索引)与 onClose(confirm-also-emits-onclose)。
  • 「取消」触发 onCancel。
  • value 越界时端侧 clamp:负数归零(clamp-negative-value-to-zero),超界归到末项 (clamp-overflow-value-to-last);空选项列表时索引恒为 0。
  • visible = false 时不发射任何绘制指令(hidden-not-rendered)。
swift
LhPicker(
  visible: $visible,
  options: options,
  value: $index,
  title: "选择",
  confirmText: "确认",
  cancelText: "取消",
  onValueChange: { newIndex in
    // 滚动吸附回调
  },
  onConfirm: { newIndex in
    // 确认回调(payload 为当前索引)
  },
  onCancel: {
    // 取消回调
  }
)

API ​

Props ​

属性说明类型默认值
visible是否显示(受控双向绑定)Bool—
options候选项文字数组(单列)[String]—
value选中项索引(受控双向绑定,越界自动 clamp)Int—
title工具栏标题String""
confirmText确认按钮文字String"确认"
cancelText取消按钮文字String"取消"
onValueChange滚动吸附回调,payload 为新索引((Int) -> Void)?nil
onConfirm确认回调,payload 为当前索引((Int) -> Void)?nil
onCancel取消回调(() -> Void)?nil
onClose关闭回调(确认 / 取消都会触发)(() -> Void)?nil

颜色 ​

区域颜色
面板底color.background.default
遮罩color.background.overlay
取消按钮 / 候选项文字color.text.primary
标题 / 确认按钮color.primary.default
指示线color.border.lighter(宽度取 cell.borderWidth)

令牌对照 ​

令牌用途
picker.height面板高度(260pt)
picker.toolbarHeight工具栏高度(44pt)
picker.itemHeight单项高度(决定滚轮与指示线间距)
picker.itemFontSize候选项与工具栏字号
picker.borderRadius顶部圆角
color.background.overlay / color.background.default遮罩与面板底色
color.border.lighter / cell.borderWidth指示线颜色与宽度
color.primary.default确认按钮与选中项文字色
zIndex.{modalBackdrop,modal}遮罩与面板的层级
motion.duration.base吸附动画时长(iOS 端为秒)

黄金用例对照 ​

case id断言本地测试
confirm-emits-onconfirm-with-value确认触发 onConfirm(1)testConfirmUsesPrimaryToken
confirm-also-emits-onclose确认同时触发 onClosetestConfirmUsesPrimaryToken
cancel-emits-oncancel取消触发 onCanceltestCancelUsesNeutralColor
scroll-emits-onvaluechange滚动吸附触发 onValueChange(2)View 层 DragGesture.onEnded(手势断言需模拟器)
clamp-negative-value-to-zero负索引 clamp 到 0testClampNegativeValueToZero
clamp-overflow-value-to-last超界索引 clamp 到末项testClampOverflowValueToLast
title-renders-text标题正确渲染testTitleAndTextsAreExposed
hidden-not-rendered隐藏时不渲染testHiddenNotRendered

另有专项:testVisibleRendersAppearance / testClampedValueIsExposed / testLayoutUsesPickerTokens / testEmptyOptionsClampsToZero / testDarkColorsComeFromDarkTokens / testDimensionsAreIdenticalInDarkMode / testPickerViewInitAcceptsConstant。

bash
swift test --filter LhPickerTests    # macOS 宿主即可跑,无需模拟器