SwiftUI 自定义选择器样式

Red*_*edX 7 xcode ios swift swiftui

我正在尝试编写一个PickerStyle看起来类似于SegmentedPickerStyle(). 这是我目前的状态:

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 {

    }
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个符合 PickerStyle 协议的结构。Xcode然后添加了所需的协议方法,但我不知道如何使用它们。有人可以解释如何处理这些方法,例如,如果我想实现类似于SegmentedPickerStyle()?

krj*_*rjw 2

自从其他事情出现以来我还没有完成它,但这是我的(未完成的实现尝试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))
    }
}
Run Code Online (Sandbox Code Playgroud)

我还没有弄清楚该值2.4所在的公式...这取决于元素的数量...她是我学到的:

2 个元素 = 4

3 个元素 = 3

4 个元素 = 2.6666

5 个元素 = 约。2.4

如果你弄清楚这一点并修复拾取器中内容的对齐,它基本上是完全可调的......你也可以通过孔物矿石使用的widthheightGeometryReader

祝你好运!

PS:我会在完成后更新它,但目前它不是我的第一要务,所以不要指望我这样做。