I try to update UIView (inside UIViewRepresentable) when the binding value changes, but I don't know how to catch the changes of the binding value to update the UIView? I used on receive function but a warning message showed say (the result of the call on receive unused)
The sample code:
struct CustomPickerView: UIViewRepresentable {
let data: [String]
@Binding var selectedValue: String
//makeCoordinator()
func makeCoordinator() -> CustomPickerView.Coordinator {
return CustomPickerView.Coordinator(self)
}
//makeUIView(context:)
func makeUIView(context: UIViewRepresentableContext<CustomPickerView>) -> UIPickerView {
let picker = UIPickerView(frame: .zero)
// allows rows to be compressed in swiftUI
picker.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
picker.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
// allows rows to be expanded
picker.setContentHuggingPriority(.defaultLow, for: .horizontal)
picker.dataSource = context.coordinator
picker.delegate = context.coordinator
picker.selectRow(data.firstIndex(of: selectedValue) ?? 0, inComponent: 0, animated: false)
return picker
}
//updateUIView(_:context:)
func updateUIView(_ view: UIPickerView, context: UIViewRepresentableContext<CustomPickerView>) {
onReceive(selectedValue.publisher) { newValue in
// I try to update the picker view selected row when binding value changes...
view.selectRow(data.firstIndex(of: newValue.debugDescription) ?? 0, inComponent: 0, animated: true)
}
}
// The rest of code ...
}
CodePudding user response:
You don't need to use onReceive
and watch the publisher -- updateUIView
will be called when selectedValue
changes, so you can use it directly:
struct ContentView: View {
@State private var selected = "3"
var body: some View {
CustomPickerView(data: ["1","2","3"], selectedValue: $selected)
Button("Choose 1") {
selected = "1"
}
}
}
struct CustomPickerView: UIViewRepresentable {
let data: [String]
@Binding var selectedValue: String
//makeCoordinator()
func makeCoordinator() -> CustomPickerView.Coordinator {
return CustomPickerView.Coordinator(self)
}
//makeUIView(context:)
func makeUIView(context: UIViewRepresentableContext<CustomPickerView>) -> UIPickerView {
let picker = UIPickerView(frame: .zero)
// allows rows to be compressed in swiftUI
picker.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
picker.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
// allows rows to be expanded
picker.setContentHuggingPriority(.defaultLow, for: .horizontal)
picker.dataSource = context.coordinator
picker.delegate = context.coordinator
picker.selectRow(data.firstIndex(of: selectedValue) ?? 0, inComponent: 0, animated: false)
return picker
}
func updateUIView(_ view: UIPickerView, context: UIViewRepresentableContext<CustomPickerView>) {
view.selectRow(data.firstIndex(of: selectedValue) ?? 0, inComponent: 0, animated: true)
}
class Coordinator : NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
parent.data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{
parent.data[row]
}
var parent: CustomPickerView
init(_ input : CustomPickerView) {
self.parent = input
}
}
}