如何让滚轮选择器中选中的中间项可以点击?
我想模仿一个滚轮选择器,类似默认的iOS日期滚轮选择器,那里的选中居中行可以点击以接受键盘数字输入。拖动中间的行也应当触发默认的滚轮选择器行为。

...
@State
var value = 0
Picker("Label", selection: self.$value) {
ForEach(0..<60, id: \.self) { el in
Text(String(el))
}
}.pickerStyle(.wheel)
我可以在整个选择器上设置一个 simultaneousGesture,但那样就无法把点击区域限制在中间行。我试着把列表项做成按钮,但看起来滚轮选择器会忽略所有自定义手势。随后我尝试添加一个透明的、可点击的覆盖层,大小和位置都对准中间行,但覆盖层后面的滚轮选择器的拖拽手势就不可用。我读到过用自定义 Binding 在 set 时触发副作用的变通方法,但我需要在点击时触发回调,而不是在选择改变时触发。我也尝试过通过覆盖 UIView.hitTest 的怪招,但并不奏效。
要实现这个,我唯一能想到的办法就是从头重新实现整个滚轮选择器。若有可能,我很想避免走这条路。
如何制作一个选中居中行可点击的滚轮选择器?
解决方案
我用一个非常蹩脚的方案让它起作用:用 GeometryReader 测量中间行的边界,把它提升到顶层状态,然后通过 simultaneousGesture 读取一个零距离拖拽手势(轻点手势似乎不提供手势位置),我手动将其起点和终点与保存的边界进行比对。
如果有人能提供更好的解决方案,我就不在这里给出答案。
@State
var value = 0
@State
var checkIsInSelectionRow: (CGPoint) -> Bool
Picker("Label", selection: self.$value) {
ForEach(0..<60, id: \.self) { el in
GeometryReader { geometry in
let frame = geometry.frame(in: .global)
Text(String(el))
.onAppear {
if el != self.value {
return
}
self.checkIsInSelectionRow = { point in
frame.minX <= point.x && point.x <= frame.maxX
&& frame.minY <= point.y && point.y <= frame.maxY
}
}
} // Pad as necessary to mitigate GeometryReader's layout-breaking
}
}.pickerStyle(.wheel)
.simultaneousGesture(
DragGesture(minimumDistance: 0.0, coordinateSpace: .global)
.onEnded { gesture in
if self.checkIsInSelectionRow(gesture.startLocation)
&& self.checkIsInSelectionRow(gesture.location)
{
// Callback
}
}
)
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。