I'm trying to write a custom PickerStyle
that looks similar to the SegmentedPickerStyle()
. This is my current status:
import SwiftUI
public struct FilterPickerStyle: PickerStyle {
public static func _makeView<SelectionValue>(value: _GraphValue<_PickerValue<FilterPickerStyle, SelectionValue>>, inputs: _ViewInputs) -> _ViewOutputs where SelectionValue : Hashable {
}
public static func _makeViewList<SelectionValue>(value: _GraphValue<_PickerValue<FilterPickerStyle, SelectionValue>>, inputs: _ViewListInputs) -> _ViewListOutputs where SelectionValue : Hashable {
}
}
I created a struct that conforms to the PickerStyle protocol. Xcode then added the required protocol methods, but I don't know how to use them. Could someone explain how to deal with these methods, if I for example want to achieve something similar to the SegmentedPickerStyle()
?
I haven't finished it yet since other stuff came up, but here is my (unfinished attempt to implement a SegmentedPicker
):
struct SegmentedPickerElementView<Content>: View where Content : View {
@Binding var selectedElement: Int
let content: () -> Content
@inlinable init(_ selectedElement: Binding<Int>, @ViewBuilder content: @escaping () -> Content) {
self._selectedElement = selectedElement
self.content = content
}
var body: some View {
GeometryReader { proxy in
self.content()
.fixedSize(horizontal: true, vertical: true)
.frame(minWidth: proxy.size.width, minHeight: proxy.size.height)
.contentShape(Rectangle())
}
}
}
struct SegmentedPickerView: View {
@Environment (\.colorScheme) var colorScheme: ColorScheme
var elements: [(id: Int, view: AnyView)]
@Binding var selectedElement: Int
@State var internalSelectedElement: Int = 0
private var width: CGFloat = 620
private var height: CGFloat = 200
private var cornerRadius: CGFloat = 20
private var factor: CGFloat = 0.95
private var color = Color(UIColor.systemGray)
private var selectedColor = Color(UIColor.systemGray2)
init(_ selectedElement: Binding<Int>) {
self._selectedElement = selectedElement
self.elements = [
(id: 0, view: AnyView(SegmentedPickerElementView(selectedElement) {
Text("4").font(.system(.title))
})),
(id: 1, view: AnyView(SegmentedPickerElementView(selectedElement) {
Text("5").font(.system(.title))
})),
(id: 2, view: AnyView(SegmentedPickerElementView(selectedElement) {
Text("9").font(.system(.title))
})),
(id: 3, view: AnyView(SegmentedPickerElementView(selectedElement) {
Text("13").font(.system(.title))
})),
(id: 4, view: AnyView(SegmentedPickerElementView(selectedElement) {
Text("13").font(.system(.title))
})),
(id: 5, view: AnyView(SegmentedPickerElementView(selectedElement) {
Text("13").font(.system(.title))
})),
]
self.internalSelectedElement = selectedElement.wrappedValue
}
func calcXPosition() -> CGFloat {
var pos = CGFloat(-self.width * self.factor / 2.4)
pos += CGFloat(self.internalSelectedElement) * self.width * self.factor / CGFloat(self.elements.count)
return pos
}
var body: some View {
ZStack {
Rectangle()
.foregroundColor(self.selectedColor)
.cornerRadius(self.cornerRadius * self.factor)
.frame(width: self.width * self.factor / CGFloat(self.elements.count), height: self.height - self.width * (1 - self.factor))
.offset(x: calcXPosition())
.animation(.easeInOut(duration: 0.2))
HStack(alignment: .center, spacing: 0) {
ForEach(self.elements, id: \.id) { item in
item.view
.gesture(TapGesture().onEnded { _ in
print(item.id)
self.selectedElement = item.id
withAnimation {
self.internalSelectedElement = item.id
}
})
}
}
}
.frame(width: self.width, height: self.height)
.background(self.color)
.cornerRadius(self.cornerRadius)
.padding()
}
}
struct SegmentedPickerView_Previews: PreviewProvider {
static var previews: some View {
SegmentedPickerView(.constant(1))
}
}
I haven't figured out the formula where the value 2.4
sits... it depends on the number of elements... her is what I have learned:
2 Elements = 4
3 Elements = 3
4 Elements = 2.6666
5 Elements = ca. 2.4
If you figure that out and fix the alignment of the content in the pickers its basically fully adjustable ... you could also pass the width
and height
of the hole thing ore use GeometryReader
Good Luck!
P.S.: I will update this when its finished but at the moment it is not my number one priority so don't expect me to do so.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With