0

I have four textFields and each takes only one character, similar to the lock screen. I can input and move from one textField to next textField.
Problem is when I want to delete and move to previous textField, I don't know when the delete button is clicked.

I'm using:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool

to input and move from one textField to another.

How do I know when the delete key is pressed?

Marcus Rossel
  • 3,196
  • 1
  • 26
  • 41
moz ado
  • 490
  • 4
  • 17

5 Answers5

4

edit/update:

Xcode 11 • Swift 5.2 or later

Follow up on this question and Swift 5 syntax can be found on this post


Original answer

Swift 1.x

Following up Istvan answer, you need to post a notification when the deleteBackward is pressed:

class DigitField: UITextField {
    override func deleteBackward() {
        super.deleteBackward()
        NSNotificationCenter.defaultCenter().postNotificationName("deletePressed", object: nil)
    }

}

Then inside viewDidLoad() you add an observer as follow:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "goPrevious", name: "deletePressed", object: nil)

and your method:

func goPrevious() {
    if secondDigit.isFirstResponder() {
        secondDigit.enabled = false
        firstDigit.enabled = true
        firstDigit.becomeFirstResponder()
    } else if thirdDigit.isFirstResponder() {
        thirdDigit.enabled = false
        secondDigit.enabled = true
        secondDigit.becomeFirstResponder()
    } else if fourthDigit.isFirstResponder() {
        fourthDigit.enabled = false
        thirdDigit.enabled = true
        thirdDigit.becomeFirstResponder()
    }
}

Select your text field and connect it to your DigitField

enter image description here

You need to connect each text field to an IBAction (using sent events editing changed)

enter image description here

The view controller code should look like this:

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var firstDigit: UITextField!
    @IBOutlet weak var secondDigit: UITextField!
    @IBOutlet weak var thirdDigit: UITextField!
    @IBOutlet weak var fourthDigit: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "goPrevious", name: "deletePressed", object: nil)
        
        firstDigit.secureTextEntry = true
        secondDigit.secureTextEntry = true
        thirdDigit.secureTextEntry = true
        fourthDigit.secureTextEntry = true

        firstDigit.keyboardType = .DecimalPad
        secondDigit.keyboardType = .DecimalPad
        thirdDigit.keyboardType = .DecimalPad
        fourthDigit.keyboardType = .DecimalPad

        firstDigit.becomeFirstResponder()
        secondDigit.enabled = false
        thirdDigit.enabled = false
        fourthDigit.enabled = false
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func goPrevious() {
        if secondDigit.isFirstResponder() {
            secondDigit.enabled = false
            firstDigit.enabled = true
            firstDigit.becomeFirstResponder()
        } else if thirdDigit.isFirstResponder() {
            thirdDigit.enabled = false
            secondDigit.enabled = true
            secondDigit.becomeFirstResponder()
        } else if fourthDigit.isFirstResponder() {
            fourthDigit.enabled = false
            thirdDigit.enabled = true
            thirdDigit.becomeFirstResponder()
        }
    }
    // You need to connect each text field to an IBAction (using sent events editing changed) – 
    @IBAction func firstChanged(sender: UITextField) {
        if let digitOne = sender.text.toInt() {
            println(digitOne)
            sender.enabled = false
            secondDigit.enabled = true
            secondDigit.becomeFirstResponder()
        } else {
            sender.text = ""
        }
    }
    
    @IBAction func secondChanged(sender: UITextField) {
        if let digitTwo = sender.text.toInt() {
            println(digitTwo)
            sender.enabled = false
            thirdDigit.enabled = true

            thirdDigit.becomeFirstResponder()
        } else {
            sender.text = ""
        }
    }
    
    @IBAction func thirdChanged(sender: UITextField) {
        if let digitThree = sender.text.toInt() {
            println(digitThree)
            sender.enabled = false
            fourthDigit.enabled = true
            fourthDigit.becomeFirstResponder()
        } else {
            sender.text = ""
        }
    }
    
    @IBAction func fourthChanged(sender: UITextField) {
        if let digitFour = sender.text.toInt() {
            println(digitFour)
            sender.enabled = false
        } else {
            sender.text = ""
        }
    }
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • looking at all the answers, this should be an easy task. but i can't get it to work. – moz ado Apr 28 '15 at 11:10
  • evrything works, except the delete. hows the DigitField class called in the view controller? – moz ado Apr 28 '15 at 11:31
  • Just select your text field and change the custom class pull down to your custom textfield you created – Leo Dabus Apr 28 '15 at 11:31
  • does the deployment target make a difference. because your deployment target was 8.3, and i changed it to 7.0. and the delete does not work on your project as well. – moz ado Apr 28 '15 at 11:41
  • i'm sorry, i have been trying to get this to work the whole day. Din't mean to be impolite, but i really appreciate your help. – moz ado Apr 28 '15 at 11:46
  • @LeoDabus Delete is working for 3 digits only once enter 4 th digit how to delete that ....? Can you please tell me that. Thanks in Advance – Raviteja Mathangi Nov 20 '19 at 05:02
  • @Madhu_Nani https://stackoverflow.com/a/63006636/2303865 – Leo Dabus Nov 16 '20 at 14:26
2

Subclass UITextField as follows:

import UIKit

class MyTextField: UITextField {
    override func deleteBackward() {
        super.deleteBackward()

        println("Delete button was tapped")
    }
}

Then change the class of your text field to MyTextField. That should do it!

Istvan
  • 1,219
  • 1
  • 8
  • 9
  • `func textField(textField: MyTextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool` . got nothing, with the above class and method. – moz ado Apr 28 '15 at 09:52
0

There is a possible solution in this answer to a similar question. You can subclass your UITextField and then override this method in your subclass:

(BOOL)keyboardInputShouldDelete:(UITextField *)textField

Event this code is in Objective-C, it should show you the proper use of this method.

Community
  • 1
  • 1
itinance
  • 11,711
  • 7
  • 58
  • 98
0

Use replacementString in function to know whats happening in UItextField

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (string.length == 0) {
        //delete
    } else {
        //any other key
    }

    return YES;
}
Paresh Navadiya
  • 38,095
  • 11
  • 81
  • 132
  • was my first approach, after the first text entry the length is always one. Tried using the string value as well, but can't get the to handle delete. – moz ado Apr 28 '15 at 09:54
0

I hope my answer will help you:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let  char = string.cStringUsingEncoding(NSUTF8StringEncoding)!
    let isBackSpace = strcmp(char, "\\b")

    if (isBackSpace == -92) {
        println("Backspace was pressed")
    }

    return true
}
Bas
  • 4,423
  • 8
  • 36
  • 53
aBilal17
  • 2,974
  • 2
  • 17
  • 23