我在 iOS 中使用分段选择器,其中包含很少的项目。当用户点击未选择的项目时,该项目将被选中。某些项目可以包含子项目。因此,当用户点击已选择的类型时,我需要显示带有子项目的模式窗口以选择其中之一。但是,无法处理分段选取器中已选定项目的点击。我尝试使用“长按”,但效果不佳。
我想使用原生 iOS 设计,这就是为什么我不想使用“按钮”而不是分段选择器。
所以问题是我如何处理点击分段选择器已选择的项目以显示子项目以选择其中之一?它可以是“长按”或其他对用户来说直观的替代方案。
import SwiftUI
struct CustomSegmentedPicker: View {
@State private var showModalSelectD: Bool = false
enum periods {
case A, B, C, D, All
}
@State var predefinedPeriod: periods = periods.All
@State var predefinedPeriodD: String = "D1"
var body: some View {
ZStack {
Color.clear
.sheet(isPresented: $showModalSelectD, content: {
List {
Picker("D", selection: $predefinedPeriodD) {
Text("D1").tag("D1")
Text("D2").tag("D2")
Text("D3").tag("D3")
}
.pickerStyle(.inline)
}
})
VStack {
HStack {
Picker("Please choose a currency", selection: $predefinedPeriod) {
Text("A").tag(periods.A)
Text("B").tag(periods.B)
Text("C").tag(periods.C)
Text("D (\(predefinedPeriodD))").tag(periods.D)
.contentShape(Rectangle())
.simultaneousGesture(LongPressGesture().onEnded { _ in
print("Got Long Press")
showModalSelectD.toggle()
})
.simultaneousGesture(TapGesture().onEnded{
print("Got Tap")
showModalSelectD.toggle()
})
Text("All").tag(periods.All)
}
.pickerStyle(SegmentedPickerStyle())
}
}
}
}
}
您可以利用分段选择器的按钮都具有相同宽度的事实。覆盖层可用于仅覆盖当前活动的选择器项目。然后,覆盖层可以拦截同一项目上的进一步点击手势。如果选择了不同的项目,覆盖层将移至该项目,依此类推。
如果覆盖层的不透明度为 0.001,那么它实际上是不可见的,但它仍然能够接收手势。
由于选择器项目都具有相同的宽度,因此可以根据总宽度轻松计算单个项目的宽度,总宽度可以使用 进行测量
GeometryReader
。然后可以通过应用 x 偏移将覆盖层移动到位。偏移量需要是项目宽度的倍数,具体取决于当前选择的索引。另一种执行定位的方法是使用
.matchedGeometryEffect
. 我发现使用项目标签作为位置的源不起作用,可能是因为项目标签被本机选择器实现“剖析”。但是,使用排列在选择器后面的一行(隐藏)占位符确实有效。下面的代码使用了
.matchedGeometryEffect
. 这需要一个命名空间:为了使实现更简单,我还制作了枚举
CaseIterable
:然后像这样应用叠加: