9

我有两个 WheelPickers 包含在 HStack 中,分别代表“小时”和“分钟”。每个 Picker 都设置在一个框架内(宽度:50,高度:30)并另外进行裁剪。

在 iOS14 中,它的行为符合预期,我可以滚动“小时”选择器来更改小时和“分钟”选择器来更改分钟。

但是在 iOS15 中,“分钟”轮选择器超出了 50 的框架宽度并重叠到“小时”选择器中;如果我在“小时”选择器上滚动,“分钟”值会发生变化(而不是“小时”值),如果我在“分钟”选择器上滚动,它会按预期改变“分钟”。如果我触摸“小时”选择器外的最左侧,则“小时”值会发生变化。

任何人都有相同的问题以及此问题的任何解决方法?

我遇到了一个解决方法来添加'mask(rectangle()'并尝试了它,但它在iOS15上不起作用。


    @State private var hour: Int = 0
    @State private var minute: Int = 0
    
    
    var body: some View {
        
        VStack {
            
            HStack (alignment: .center, spacing: 3) {
                
                NumberPicker("", selection: $hour
                                 , startValue: 0
                                 , endValue: 23
                                 , pickerSize: CGSize(width: 50, height: 30)
                )

                Text("hr")
                
                NumberPicker("", selection: $minute
                                 , startValue: 0
                                 , endValue: 59
                                 , pickerSize: CGSize(width: 50, height: 30)
                )

                Text("min")

            } // HStack
            
        } // VStack

    }

}
struct NumberPicker: View {
    
    let startValue: Int
    let endValue: Int
    let pickerSize: CGSize
    let title: String
    
    @Binding var selection: Int
    @State var value: Int = 0
    
    init(_ title: String = ""
         , selection: Binding<Int>
         , startValue: Int = 0
         , endValue: Int
         , pickerSize: CGSize = CGSize(width: 50, height: 30)
    ) {
        self._selection = selection
        self.title = title
        self.startValue = startValue
        self.endValue = (endValue + 1)
        self.pickerSize = pickerSize
        
        self._value = State(initialValue: selection.wrappedValue)
    }
    
    
    var body: some View {
        
        Picker(title, selection: $value) {
            
            ForEach(startValue..<endValue, id: \.self) { currentValue in
                
                Text("\(currentValue)")
                    .tag(currentValue)
            }
        }
        .pickerStyle(WheelPickerStyle())
        .fixedSize(horizontal: true, vertical: true)
        .frame(width: pickerSize.width, height: pickerSize.height)
        .clipped(antialiased: true)
    }
}
4

4 回答 4

9

NumberPicker尝试添加compositingGroup之前clipped(...)作为:

.compositingGroup()
.clipped(antialiased: true)
于 2021-09-09T23:46:48.973 回答
9

在 iOS 15.1 中似乎没有任何解决方法,所以我自己使用UIViewRepresentable. 该示例是为我使用而制作的,Double但您可以轻松地将其调整为适合您的。

除了能够在单个轮式拾取器中拥有多个组件外,您还可以HStack毫无问题地将它们水平堆叠:

用法

import SwiftUI

struct ContentView: View {
    
    @State private var selections1: [Double] = [5, 10]
    
    private let data1: [[Double]] = [
        Array(stride(from: 0, through: 60, by: 1)),
        Array(stride(from: 0, through: 60, by: 1))
    ]
    
    var body: some View {
        VStack {
            HStack{
                MultiWheelPicker(selections: self.$selections1, data: data1)
                    .frame(width: 150)
                MultiWheelPicker(selections: self.$selections1, data: data1)
                    .frame(width: 150)
            }
        }
        
    }
}

看法

struct MultiWheelPicker: UIViewRepresentable {
    var selections: Binding<[Double]>
    let data: [[Double]]
    
    func makeCoordinator() -> MultiWheelPicker.Coordinator {
        Coordinator(self)
    }
    
    func makeUIView(context: UIViewRepresentableContext<MultiWheelPicker>) -> 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<MultiWheelPicker>) {
        for comp in selections.indices {
            if let row = data[comp].firstIndex(of: selections.wrappedValue[comp]) {
                view.selectRow(row, inComponent: comp, animated: false)
            }
        }
    }
    
    class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
        var parent: MultiWheelPicker
      
        init(_ pickerView: MultiWheelPicker) {
            parent = pickerView
        }
        
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            return parent.data.count
        }
        
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            return parent.data[component].count
        }
        
        func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
            return 48
        }
        
        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
            return String(format: "%02.0f", parent.data[component][row])
        }
        
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            parent.selections.wrappedValue[component] = parent.data[component][row]
        }
    }
}
于 2021-11-04T16:04:16.687 回答
0

我添加.pickerStyle(WheelPickerStyle())到 Picker 视图并在我的 iOS 15 代码中解决了这个问题。

于 2022-01-25T20:00:51.733 回答
0

我试图改进 Steve M 提供的解决方案,但预览崩溃了。有人可以纠正这个:

我对 Swift UI 比较陌生,但对编程并不陌生。不过,我仍然没有完全掌握所有 SwiftUI 概念。

import SwiftUI

struct CustomDatePicker: View {
    let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
    let daysOfMonth = Array(1...31)
    @State private var monthSelected = "January"
    @State private var daySelected = 1

    private let numberFormatter: NumberFormatter = {
        let nf = NumberFormatter()
        nf.usesGroupingSeparator = false
        return nf
    }()

    @State private var selections1: [String] = []
    
    @State private var selections2: [Double] = []
    
    private let data1: [[String]] = [
        Array(["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"])
    ]

    private let data2: [[Double]] = [
        Array(stride(from: 0, through: 60, by: 1))
    ]
    
    var body: some View {
        VStack {
            HStack{
                MultiWheelPicker(selections: self.$selections1, data: data1)
                    .frame(width: 450)
                MultiWheelPicker(selections: self.$selections2, data: data2)
                    .frame(width: 450)
            }
        }
    }
}

struct YearPicker_Previews: PreviewProvider {
    static var previews: some View {
        CustomDatePicker()
    }
}

struct MultiWheelPicker<T:Equatable>: UIViewRepresentable {
    var selections: Binding<[T]>
    let data: [[T]]
    
    func makeCoordinator() -> MultiWheelPicker.Coordinator {
        Coordinator(self)
    }
    
    func makeUIView(context: UIViewRepresentableContext<MultiWheelPicker>) -> 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<MultiWheelPicker>) {
        for comp in selections.indices {
            if let row = data[comp].firstIndex(of: selections.wrappedValue[comp]) {
                view.selectRow(row, inComponent: comp, animated: false)
            }
        }
    }
    
    class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
        var parent: MultiWheelPicker
      
        init(_ pickerView: MultiWheelPicker) {
            parent = pickerView
        }
        
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            return parent.data.count
        }
        
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            return parent.data[component].count
        }
        
        func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
            return 48
        }
        
        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
            return parent.data[component][row] as? String
        }
        
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            parent.selections.wrappedValue[component] = parent.data[component][row]
        }
    }
}
于 2022-01-29T12:10:27.143 回答