SwiftUI - Prevent users from adding New Line (\n) in TextEditor

Viewed 1329

I have a TextEditor that I do not let users add New Line (\n) in it. That is to say, when a user Enter, I dismiss the keyboard. I have used the following code to dismiss the keybaord and prevents users from adding a new line.

The keyboard is dismissed on Enter, but it does not prevent users from adding a new line. When you Enter.

extension View {
  func  dismissKeyboard(){
        let keyWindow = UIApplication.shared.connectedScenes
                .filter({$0.activationState == .foregroundActive})
                .map({$0 as? UIWindowScene})
                .compactMap({$0})
                .first?.windows
                .filter({$0.isKeyWindow}).first
        keyWindow?.endEditing(true)
    }
}


struct Editor: View {
    
    @Binding var text: String
        
    var onEditingEnded: () -> ()
    
    var body: some View {
        ZStack(alignment: .leading) {         
            TextEditor(text: $text)
                .onChange(of: text) { value in
                    if value.last == "\n" {
                        self.dismissKeyboard()
                        self.onEditingEnded()
                    }
                }
        }
        .padding(8)
        .font(.body)
    }
}

How to prevent users from adding a new line?

2 Answers

You could use a UITextView which has a shouldChangeTextIn range delegate function...

Or, while not what I'd call ideal, this could work for you:

TextEditor(text: $text)
            
    .onChange(of: text) { value in
        if value.last == "\n" {
            text = String(value.dropLast())
            self.dismissKeyboard()
            self.onEditingEnded()
        }
    }

Note that you're checking only the last character in the string, so this won't handle a user adding a newline in the middle of existing text.

So, you might instead try:

TextEditor(text: $text)

    .onChange(of: text) { value in
        if value.contains("\n") {
            text = value.replacingOccurrences(of: "\n", with: "")
            self.dismissKeyboard()
            self.onEditingEnded()
        }
    }

Similar to DonMag's answer, you can also use Binding() instead of .onChange() to avoid changing the value afterwards and act before it is being set:

TextEditor(text: Binding(
    get: {
        return text
    },
    set: { value in
        var newValue = value
        if value.contains("\n") {
            newValue = value.replacingOccurrences(of: "\n", with: "")
            self.dismissKeyboard()
            self.onEditingEnded()
        }
        text = newValue
    }
))
Related