Is there any way to set inputView for TextField in SwiftUI?

。_饼干妹妹 提交于 2021-01-21 08:38:24

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!