Eu uso o seletor segmentado no iOS, que contém poucos itens. Quando o usuário toca em um item não selecionado, este item é selecionado. Alguns itens podem conter subitens. Portanto, quando o usuário toca no tipo já selecionado, preciso mostrar a janela modal com subitens para escolher um deles. Mas os toques em itens já selecionados do seletor segmentado não estão funcionando. Tentei usar "pressão longa", mas não funcionou tão bem.
Eu gostaria de usar o design nativo do iOS, por isso não quero usar "botões" em vez do seletor segmentado.
Então a questão é como posso tocar em um item já selecionado do seletor segmentado para mostrar subitens e escolher um deles? Pode ser um “pressionamento longo” ou outra alternativa que seja intuitiva para o usuário.
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())
}
}
}
}
}
Você pode aproveitar o fato de que todos os botões de um seletor segmentado têm larguras iguais. Uma sobreposição pode ser usada para cobrir apenas o item do seletor que está ativo no momento. A sobreposição pode então interceptar outros gestos de toque no mesmo item. Se um item diferente for selecionado, a sobreposição se moverá para esse item, etc.
Se a sobreposição receber uma opacidade de 0,001, ela ficará efetivamente invisível, mas ainda será capaz de receber gestos.
Como todos os itens do seletor têm larguras iguais, a largura de um único item pode ser calculada facilmente a partir da largura total, que pode ser medida usando um
GeometryReader
. A sobreposição poderia então ser movida para a posição aplicando um deslocamento x. O deslocamento precisa ser um múltiplo da largura do item, dependendo do índice da seleção atual.Outra forma de realizar o posicionamento seria usar
.matchedGeometryEffect
. Descobri que usar os rótulos dos itens como fonte da posição não funciona, talvez porque os rótulos dos itens sejam "dissecados" pela implementação do seletor nativo. No entanto, funciona usar uma linha de espaços reservados (ocultos) dispostos atrás do seletor.O código abaixo usa a técnica de
.matchedGeometryEffect
. Isso requer um namespace:Para tornar a implementação um pouco mais simples, fiz também o enum
CaseIterable
:A sobreposição é então aplicada assim: