3

我目前正在尝试创建一个包含三个相邻Picker视图的页面,HStack如下所示:

在此处输入图像描述

我做了一个CustomPicker视图,将框架限制为 90 x 240,然后使用.compositingGroup().clipped()使每个选择器的可选区域不重叠。

CustomPicker.swift

import SwiftUI

struct CustomPicker: View {
    @Binding var selection: Int
    let pickerColor: Color
    
    var numbers: some View {
        ForEach(0...100, id: \.self) { num in
            Text("\(num)")
                .bold()
        }
    }
    
    var stroke: some View {
        RoundedRectangle(cornerRadius: 16)
            .stroke(lineWidth: 2)
    }
    
    var backgroundColor: some View {
        pickerColor
            .opacity(0.25)
    }
    
    var body: some View {
        Picker("Numbers", selection: $selection) {
            numbers
        }
        .frame(width: 90, height: 240)
        .compositingGroup()
        .clipped()
        .pickerStyle(.wheel)
        .overlay(stroke)
        .background(backgroundColor)
        .cornerRadius(16)
    }
}

ChoicePage.swift

struct ChoicePage: View {
    @State var choiceA: Int = 0
    @State var choiceB: Int = 0
    @State var choiceC: Int = 0
    
    var body: some View {
        HStack(spacing: 18) {
            CustomPicker(selection: $choiceA, pickerColor: .red)
            CustomPicker(selection: $choiceB, pickerColor: .green)
            CustomPicker(selection: $choiceC, pickerColor: .blue)
        }
    }
}

CustomPicker在预览画布和模拟器中进行测试时ChoicePage,它工作得非常好,但是当我尝试在我的物理设备(iPhone 8 和 iPhone 13,都在 iOS 15.1 上)上使用它时,可点击区域重叠。我已经尝试了这篇文章这篇文章以及许多其他文章的解决方案,但似乎没有什么对我有用。

4

1 回答 1

2

我通过修改Steve M的解决方案解决了这个问题,所以这一切都归功于他。

他使用 a UIViewRepresentable,但在他的实现中,它用于一个内的三个不同的选择。我稍微调整了他的实现,只用于在给定选择器中选择一个值。

我从 开始BasePicker,它充当UIViewRepresentable

BasePicker.swift

struct BasePicker: UIViewRepresentable {
    var selection: Binding<Int>
    let data: [Int]
    
    init(selecting: Binding<Int>, data: [Int]) {
        self.selection = selecting
        self.data = data
    }
    
    func makeCoordinator() -> BasePicker.Coordinator {
        Coordinator(self)
    }
    
    func makeUIView(context: UIViewRepresentableContext<BasePicker>) -> UIPickerView {
        let picker = UIPickerView()
        picker.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        picker.dataSource = context.coordinator
        picker.delegate = context.coordinator
        return picker
    }
    
    func updateUIView(_ view: UIPickerView, context: UIViewRepresentableContext<BasePicker>) {
        guard let row = data.firstIndex(of: selection.wrappedValue) else { return }
        view.selectRow(row, inComponent: 0, animated: false)
    }
    
    class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
        var parent: BasePicker
        
        init(_ pickerView: BasePicker) {
            parent = pickerView
        }
        
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            return 1
        }
        
        func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
            return 90
        }
        
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            return parent.data.count
        }
        
        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
            return parent.data[row].formatted()
        }
        
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            parent.selection.wrappedValue = parent.data[row]
        }
    }
}

然后我在 SwiftUI 中使用BasePickerRepresentable 。我这样做是为了更容易将我以前的样式/结构保留在原始代码中。CustomPickerView

CustomPicker.swift

struct CustomPicker: View {
    @Binding var selection: Int
    let pickerColor: Color

    let numbers: [Int] = Array(stride(from: 0, through: 100, by: 1))
    
    var stroke: some View {
        RoundedRectangle(cornerRadius: 16)
            .stroke(lineWidth: 2)
    }
    
    var backgroundColor: some View {
        pickerColor
            .opacity(0.25)
    }
    
    var body: some View {
        BasePicker(selecting: $selection, data: numbers)
            .frame(width: 90, height: 240)
            .overlay(stroke)
            .background(backgroundColor)
            .cornerRadius(16)
    }
}

然后我只需要稍微改变ChoicePage一下就可以了。另外,请注意我将numbers数组移到了我的CustomPicker视图中,但是您对其进行了调整,以便您可以根据需要将其传入ChoicePage

ChoicePage.swift

struct ChoicePage: View {
    @State var choiceA: Int = 0
    @State var choiceB: Int = 0
    @State var choiceC: Int = 0
    
    var body: some View {
        HStack(spacing: 18) {
            CustomPicker(selection: $choiceA, pickerColor: .red)
            CustomPicker(selection: $choiceB, pickerColor: .green)
            CustomPicker(selection: $choiceC, pickerColor: .blue)
        }
    }
}
于 2021-12-13T06:31:26.780 回答