altec
altec

Reputation: 165

Press return key "without" dismissing software keyboard - SwiftUI

I'd like to create a TextField, where it's possible to quickly enter multiple String items into the same field, by typing in the item, then hitting return to add it.

I've already got the adding functionality, however I don't want to dismiss the keyboard each time an item is added to the list upon hitting return, as that's cumbersome for the users to tap the textfield each time in order to bring back the keyboard.

I'm looking for a pure SwiftUI solution if possible.

What I've got:

import SwiftUI

struct StackOverflowSubmissions: View {

   @State var item: String = ""
   var body: some View {

      TextField("Enter item...", text: $item, onCommit: {

         // Add item to CoreData database

      })
         .textFieldStyle(RoundedBorderTextFieldStyle())
         .padding(5)
         .background(Color(.gray))
         .cornerRadius(10)
         .padding()
    }
}

struct StackOverflowSubmissions_Previews: PreviewProvider {
    static var previews: some View {
        StackOverflowSubmissions()
    }
}


Upvotes: 3

Views: 2334

Answers (1)

Md. Yamin Mollah
Md. Yamin Mollah

Reputation: 1801

Here is the CustomTextField that does not minimise the keyboard instead the next CustomTextView is focused. This process continues until the current CustomTextField is the last CustomTextField.

struct CustomTextField: UIViewRepresentable {
    @Binding var text: String // String value of the TextView
    let placeholder: String // Placeholder Text
    let keyboardType: UIKeyboardType // Keypad layout type
    let tag: Int // Tag to recognise each specific TextView
    var commitHandler: (()->Void)? // Called when return key is pressed

    init(_ placeholder: String, text: Binding<String>, keyboardType: UIKeyboardType, tag: Int, onCommit: (()->Void)?) {
        self._text = text
        self.placeholder = placeholder
        self.tag = tag
        self.commitHandler = onCommit
        self.keyboardType = keyboardType
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> UITextField {
        // Customise the TextField as you wish
        let textField = UITextField(frame: .zero)
        textField.keyboardType = self.keyboardType
        textField.delegate = context.coordinator
        textField.backgroundColor = UIColor(white: 0.0, alpha: 0.025)
        textField.layer.borderWidth = 0.5
        textField.layer.borderColor = UIColor.tertiaryLabel.cgColor
        textField.font = UIFont.systemFont(ofSize: 16.0, weight: .light)
        textField.layer.cornerRadius = 6
        textField.isUserInteractionEnabled = true
        textField.text = text
        textField.textColor = UIColor.lightGray
        textField.tag = tag
        textField.placeholder = placeholder

        // For left inner padding
        let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: 120))
        textField.leftView = paddingView
        textField.leftViewMode = UITextField.ViewMode.always

        return textField
    }

    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = self.text
        uiView.setContentHuggingPriority(.init(rawValue: 70), for: .vertical)
        uiView.setContentHuggingPriority(.defaultLow, for: .horizontal)
    }

    class Coordinator : NSObject, UITextFieldDelegate {

        var parent: CustomTextField

        init(_ uiTextView: CustomTextField) {
            self.parent = uiTextView
        }

        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

            if let value = textField.text as NSString? {
                let proposedValue = value.replacingCharacters(in: range, with: string)
                parent.text = proposedValue as String
            }
            return true
        }

        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            if let nextTextField = textField.superview?.superview?.viewWithTag(textField.tag + 1) as? UITextField {
                nextTextField.becomeFirstResponder()
            } else {
                textField.resignFirstResponder()
            }
            return false
        }

        func textFieldDidEndEditing(_ textField: UITextField) {
            parent.commitHandler?()
        }
    }
}

Use CustomTextView in the ContentView like this:

struct ContentView: View {
    @State var firstName: String = ""
    @State var lastName: String = ""
    @State var email: String = ""

    var body: some View {
        VStack {
            Text("First Name Value: \(firstName)")
            CustomTextField("First Name", text: self.$firstName, keyboardType: .default, tag: 1, onCommit: nil).padding().frame(height: 70)


            Text("Last Name Value: \(lastName)")
            CustomTextField("Last Name", text: self.$lastName, keyboardType: .default, tag: 2, onCommit: {
                    print("Last Name is: \(self.lastName)")
                }).padding().frame(minWidth: 0, maxWidth: .infinity, minHeight: 70, maxHeight: 70)


            Text("Email Value: \(email)")
            CustomTextField("Email", text: self.$email, keyboardType: .emailAddress, tag: 3, onCommit: {
                    print("Email is: \(self.email)")
                }).padding().frame(minWidth: 0, maxWidth: .infinity, minHeight: 70, maxHeight: 70)
        }
    }
}

Upvotes: 2

Related Questions