首页 > 解决方案 > 如何在 SwiftUI 中使用多个 Picker 更改 UIPickerView 的宽度?

问题描述

我需要使用 UIPickerView 而不是 SwiftUI Picker,因为它存在一些错误,我需要对它进行更多控制。

下面的方法一切正常,但是,我需要一个宽度较小的选择器(大约是原始宽度的 70%),但仍然显示所有三个选择器并且仍然具有灰色背景的圆角(所以灰色背景框架宽度和三个拾取器之间的间距应该减小)。

我试图修改选择器的框架及其超级视图,但这根本不起作用。在 SwiftUI 中设置帧宽度,然后使用 clipped 修饰符会切断圆角边缘并切断数字的某些部分(所以这是不可能的)。

有人知道该怎么做吗?非常感谢!

在此处输入图像描述

import SwiftUI

struct ContentView: View {

    @State private var selections: [Int] = [5, 10, 50]

    var body: some View {
        MainPicker(pickerSelections: self.$selections)
    }
}

struct MainPicker: View {
    
    @Binding var pickerSelections: [Int]
    
    private let data: [[String]] = [
        Array(0...59).map { "\($0 < 10 ? "0" : "")" + "\($0)" },
        Array(0...59).map { "\($0 < 10 ? "0" : "")" + "\($0)" },
        Array(0...59).map { "\($0 < 10 ? "0" : "")" + "\($0)" }
    ]
    
    var body: some View {
        HStack{
            PickerView(data: data, selections: self.$pickerSelections)
        }
    }
}

struct PickerView: UIViewRepresentable {
    var data: [[String]]
    @Binding var selections: [Int]

    //makeCoordinator()
    func makeCoordinator() -> PickerView.Coordinator {
        Coordinator(self)
    }

    //makeUIView(context:)
    func makeUIView(context: UIViewRepresentableContext<PickerView>) -> UIPickerView {

        let hoursLabel = UILabel()
        let minLabel = UILabel()
        let secLabel = UILabel()
        hoursLabel.text = "h"
        minLabel.text = "m"
        secLabel.text = "s"
        
        let picker = UIPickerView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) //doesnt work
        
        
        picker.dataSource = context.coordinator
        picker.delegate = context.coordinator
        
        picker.superview?.frame = CGRect(x: 0, y: 0, width: 100, height: 100) //doesnt work
        
        return picker
    }

    //updateUIView(_:context:)
    func updateUIView(_ view: UIPickerView, context: UIViewRepresentableContext<PickerView>) {
        for i in 0...(self.selections.count - 1) {
            if(context.coordinator.initialSelection[i] != self.selections[i]){
                view.selectRow(self.selections[i], inComponent: i, animated: false)
                context.coordinator.initialSelection[i] = self.selections[i]
            }
        }
    }

    class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
        var parent: PickerView
        var initialSelection = [-1, -1, -1]
        
        //init(_:)
        init(_ pickerView: PickerView) {
            
            self.parent = pickerView
        }

        //numberOfComponents(in:)
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            return self.parent.data.count
        }

        //pickerView(_:numberOfRowsInComponent:)
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            return self.parent.data[component].count
        }
        
        func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
            return 50
        }

        //pickerView(_:titleForRow:forComponent:)
        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
            return self.parent.data[component][row]
        }

        //pickerView(_:didSelectRow:inComponent:)
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            self.parent.selections[component] = row
        }
    }
}

标签: iosswiftswiftuiuikit

解决方案


您需要删除抗压优先级

let picker = UIPickerView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
picker.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

然后可以在 SwiftUI 部分中根据需要使用任何框架(静态或计算)

演示

    MainPicker(pickerSelections: self.$selections)
        .frame(width: 200)

使用 Xcode 11.7 / iOS 13.7 准备和测试的演示


推荐阅读