问题
I want to set picker as my inputView for TextField, can I do it with SwiftUI only or I have to use UIKit components with help of framework integration?
Code example in UIKit:
textField.inputView = UIPickerView()
I want to do same, but with SwiftUI's TextField
回答1:
As of Xcode 11.4, SwiftUI's TextField does not have an equivalent of the inputView property of UITextField.
You can work around it by bridging a UIKit UITextField to SwiftUI, and by bridging a SwiftUI Picker to UIKit. You'll need to set the text field's inputViewController property rather than its inputView property.
To bridge a UITextField to SwiftUI
Use UIViewRepresentable to wrap the UITextField in a SwiftUI View. Since you create the UITextField, you can set its inputViewController property to a UIViewController that you create.
To bridge a SwiftUI Picker into UIKit
UseUIHostingController to wrap a SwiftUI Picker in a UIViewController. Set the text field's inputViewController to your UIHostingController instance.
回答2:
The only issue which I found using the above-mentioned solution was that whenever the keyboard gets into the editing phase, then the picker was presented and along with it the keyboard also gets presented.
So there was no way to hide the keyboard and present the picker. Therefore I have written a custom struct to handle this behaviour similar to what we do using UITextField inputView. You can use it. This works for my use case.
You can also customise the picker, as well as textfield in the makeUIView methods like I, have done with the background colour of the picker.
struct TextFieldWithPickerAsInputView : UIViewRepresentable {
var data : [String]
var placeholder : String
@Binding var selectionIndex : Int
@Binding var text : String?
private let textField = UITextField()
private let picker = UIPickerView()
func makeCoordinator() -> TextFieldWithPickerAsInputView.Coordinator {
Coordinator(textfield: self)
}
func makeUIView(context: UIViewRepresentableContext<TextFieldWithPickerAsInputView>) -> UITextField {
picker.delegate = context.coordinator
picker.dataSource = context.coordinator
picker.backgroundColor = .yellow
picker.tintColor = .black
textField.placeholder = placeholder
textField.inputView = picker
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<TextFieldWithPickerAsInputView>) {
uiView.text = text
}
class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate , UITextFieldDelegate {
private let parent : TextFieldWithPickerAsInputView
init(textfield : TextFieldWithPickerAsInputView) {
self.parent = textfield
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return self.parent.data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return self.parent.data[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.parent.$selectionIndex.wrappedValue = row
self.parent.text = self.parent.data[self.parent.selectionIndex]
self.parent.textField.endEditing(true)
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.parent.textField.resignFirstResponder()
}
}
}
You can use this as:-
struct ContentView : View {
@State var gender : String? = nil
@State var arrGenders = ["Male","Female","Unknown"]
@State var selectionIndex = 0
var body : some View {
VStack {
TextFieldWithPickerAsInputView(data: self.arrGenders, placeholder: "select your gender", selectionIndex: self.$selectionIndex, text: self.$gender)
}
}
}
回答3:
If you want to have a TextField and choose its text using a Picker in SwiftUI. And you don't want to integrate UIKit in SwiftUI, the bellow solution may give you some ideas:
import SwiftUI
struct ContentView: View {
@State private var selection = 0
@State private var textfieldValue = ""
@State private var textfieldValue2 = ""
@State private var ispickershowing = false
var values = ["V1", "V2", "V3"]
var body: some View {
VStack {
TextField("Pick one from the picker:", text: $textfieldValue, onEditingChanged: {
edit in
if edit {
self.ispickershowing = true
} else {
self.ispickershowing = false
}
})
if ispickershowing {
Picker(selection: $selection, label:
Text("Pick one:")
, content: {
ForEach(0 ..< values.count) { index in
Text(self.values[index])
.tag(index)
}
})
Text("you have picked \(self.values[self.selection])")
Button(action: {
self.textfieldValue = self.values[self.selection]
}, label: {
Text("Done")
})
}
TextField("simple textField", text: $textfieldValue2)
}
}
}
来源:https://stackoverflow.com/questions/57975634/is-there-any-way-to-set-inputview-for-textfield-in-swiftui