iOS15 - SwiftUI WheelPicker 可滚动外框和剪切区域破坏其他界面

use*_*201 13 swiftui ios15

我在 HStack 中包含两个 WheelPicker,分别表示“小时”和“分钟”。每个选取器都设置在一个框架内(宽度: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

    }

}
Run Code Online (Sandbox Code Playgroud)
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)
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*e M 11

在 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)
            }
        }
        
    }
}
Run Code Online (Sandbox Code Playgroud)

看法

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]
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


wor*_*dog 9

尝试在之前NumberPicker添加:compositingGroupclipped(...)

.compositingGroup()
.clipped(antialiased: true)
Run Code Online (Sandbox Code Playgroud)

  • 谢谢@workingdog。这解决了问题,但现在我在 15.1 版本和 15.2 beta 版本中再次发生同样的事情。这次有修复吗? (3认同)