Detect Backspace Event on TextField using Subclass or Delegate Solution Integration problem
Asked Answered
S

2

1

To preface, this problem has been solved using a couple of different methods - I'll leave the stack overflow post that has the solution here text

The problem deals with detecting when the "delete" or "backspace" button has been pressed on the iOS keyboard. I specifically want to be able to detect when the button has been pressed on an empty TextField

I've been stuck on integrating a solution and I think it's from lack of understanding some intermediary steps.

Here are the solutions that have been posed that I know can work.

The first is integrating this delegate function:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if let char = string.cString(using: String.Encoding.utf8) {
        let isBackSpace = strcmp(char, "\\b")
        if (isBackSpace == -92) {
            print("Backspace was pressed") // Or prefrom some operation 
        }
    }
    return true
}

The second is to subclass the UITextfield Class and create an override function:

class MyTextField: UITextField {
    override public func deleteBackward() {
        if text == "" {
             // do something when backspace is tapped/entered in an empty text field
        }
        // do something for every backspace
        super.deleteBackward()
    }
}

The specific functionality that I want to achieve is switching @FocuState Variables within a content view. So for example : If (Second) TextField().isEmpty and "delete" key is pressed, then FocusStateOne = true.

Here is a basic content view with a couple different TextFields:

struct ContentView: View {
    @State private var textOne = ""
    @State private var textTwo = ""
    @FocusState private var oneFocus: Bool

    var body: some View {
        VStack {
            TextField("",text: $textOne)
  
                .padding()
                .focused($oneFocus)

            TextField("",text: $textTwo)
                .padding()

// Detect if TextField is empty and if "delete" is pressed, then @FocusState var oneFocus = true



            Text("Entered text: \(textOne)")
                .padding()
            Text("Entered text: \(textTwo)")
                .padding()
        }
    }
}

I've tried subclassing, this makes the most sense to me, but I don't understand how the subclass with be able to conform to a view struct and communicate / change the variables within that view. It seems like I'd have to write some other kind of function that could communicate with the variables inside of the content view, but I'm unsure.

As far as delegates go, I understand the basics of what a delegate function is, but can't seem to figure out how I can implement it into a basic content view.

Most times I try either of these solutions I get Scope related issues, I think there is a lot I'm not understanding / doing correctly.

Of these two solutions, which one is better in the context of what I'm trying to do? I'm just a little lost on the "in-between" steps. I'm a complete beginner to Swift.

Seringa answered 14/7, 2023 at 5:27 Comment(2)
is this for UIKit only? You describe some UIKit solutions, but then you have SwiftUI struct ContentView: View with SwiftUI TextField(...). Are you after a solution for SwiftUI?Laicize
Yes - Sorry that was unclear, I am working in swiftUI and ultimately want to find a solution that's compatible with SwiftUI. Thanks!Seringa
B
1

There is a swiftui modifier as given below with which we can check and perform anything when its value changes like I have done below. But the point is it will work only when there is change in value. For the first time if the filed is empty and you presses backspace or delete, it will not work as there is no change in value. So you can attach the following modifier to second textfield and text its flow.

.onChange(of: textTwo) { newValue in
                    if newValue.isEmpty {
                        oneFocus = true
                    }
                }

Let me know it is what you want. If so then good otherwise leave me a comment, we can discuss about it.

Bicipital answered 14/7, 2023 at 6:19 Comment(2)
Hi! Thanks for getting back to me! I'm a big fan of using the .onChange() Modifier, it works great, but like you said, it doesn't work on if there isn't a change in the text field and the user pressed "delete". Do you have any other ideas that could potentially work? Thank you for getting back to me so quickly!Seringa
I think this is not a common behavior in apps. If you really want to do it. Then probably you have play with textfields delegate and that would be trickier. However you can play with it, if you really need it. You can either accept my answer or upvote it if you think it is helpful. ThanksBicipital
M
1

This is a very common problem, wrapping a custom UITextField so we can detect when delete key is pressed overriding deleteBackward() and then creating and component that conforming UIViewRepresentable protocol will expose our custom UITextField to SwiftUI, has proven to be the most effective approach I've discovered so far and works as expected. Here you can find a simple use case(screen with 4 textfields to enter 4 characters code see picture bellow) and it's full implementation. Hope it helps.

PD: This example covers the scenario when the delete key is pressed and the text field is empty

enter image description here

Mignonne answered 19/11, 2023 at 16:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.