filipealva / PickerView

🔸 A customizable alternative to UIPickerView in Swift.
MIT License
527 stars 92 forks source link

SwiftUI - cellForRowAtIndexPath never called in UIViewRepresentable #53

Open spike-hue opened 3 years ago

spike-hue commented 3 years ago

I'm trying to use this library in SwiftUI but there seems to be an issue. When I present the picker, nothing is shown. I set breakpoint and cellForRowAtIndexPath is never called.

I searched online and another person is having the same exact issue: https://stackoverflow.com/questions/57297895/swiftui-uitableview-cellforrowatindexpath-never-called-in-uiviewrepresentable

Here is the code in StackOverflow that is very similar to mine that doesn't work:

struct FruitPicker: UIViewRepresentable {
    @Binding var fruits: [Fruit]
    @Binding var selectedFruit: Fruit

    class Coordinator: NSObject, PickerViewDelegate, PickerViewDataSource {
        @Binding var fruits: [Fruit]
        @Binding var selectedFruit: Fruit

        init(fruits: Binding<[Fruit]>, selectedFruit: Binding<Fruit>) {
            self._fruits = fruits
            self._selectedFruit = selectedFruit
        }

        func pickerViewNumberOfRows(_ pickerView: PickerView) -> Int {
            return self.fruits.count
        }

        func pickerViewHeightForRows(_ pickerView: PickerView) -> CGFloat {
            return 50
        }

        func pickerView(_ pickerView: PickerView, titleForRow row: Int) -> String {
            return self.fruits[row].name
        }

        func pickerView(_ pickerView: PickerView, didSelectRow row: Int) {
            self.selectedFruit = self.fruits[row]
        }
    }

    func makeCoordinator() -> FruitPicker.Coordinator {
        return Coordinator(fruits: self.$fruits, selectedFruit: self.$selectedFruit)
    }

    func makeUIView(context: UIViewRepresentableContext<FruitPicker>) -> PickerView {
        let pickerView = PickerView()

        pickerView.delegate = context.coordinator
        pickerView.dataSource = context.coordinator

        return pickerView
    }

    func updateUIView(_ pickerView: PickerView, context: UIViewRepresentableContext<FruitPicker>) {

    }
}

Could you please help out with this?

spike-hue commented 3 years ago

@filipealva Any thoughts on this? Hopefully you can take a look

aspcartman commented 3 years ago

@johnswifttt I faced same issue. For some reason the PickerView really wants to collapse to zero size. TableView doesn't call the cell for row if it's too small to display it.

The quick fix is adding var builtConstraints: Bool = false to coordinator and

if !context.coordinator.builtConstraints && pickerView.superview != nil  {
    let constraints = [
        NSLayoutConstraint(item: pickerView, attribute: .height, relatedBy: .equal, toItem: pickerView.superview,
                           attribute: .height, multiplier: 1, constant: 0),
        NSLayoutConstraint(item: pickerView, attribute: .width, relatedBy: .equal, toItem: pickerView.superview,
                           attribute: .width, multiplier: 1, constant: 0)

    ]
    pickerView.superview?.addConstraints(constraints)
    context.coordinator.builtConstraints = true
}

into the update func, hoping that superview doesn't change : ) Seems to work for me.