Je cherche des solutions sur la façon de capturer un événement de retour arrière, la plupart des réponses Stack Overflow sont en Objective-C mais j'ai besoin de la langue Swift.
J'ai d'abord défini délégué pour UITextField et je l'ai défini sur self
self.textField.delegate = self;
Ensuite, je sais utiliser la méthode déléguée shouldChangeCharactersInRange
pour détecter si un retour arrière a été enfoncé si tout le code est en Objective-C. J'ai besoin en Swift ces méthodes suivantes comme ci-dessous sont utilisées.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
const char * _char = [string cStringUsingEncoding:NSUTF8StringEncoding];
int isBackSpace = strcmp(_char, "\b");
if (isBackSpace == -8) {
// NSLog(@"Backspace was pressed");
}
return YES;
}
Swift 4.2
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")
}
}
return true
}
Ancienne Swift version
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
}
Dans Swift
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let char = string.cString(using: String.Encoding.utf8)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
}
return true
}
:)
Je préfère sous-classer UITextField
et remplacer deleteBackward()
parce que c'est beaucoup plus fiable que le hack d'utiliser shouldChangeCharactersInRange
:
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()
}
}
Le hack shouldChangeCharactersInRange
combiné à un caractère invisible placé dans le champ de texte présente plusieurs inconvénients:
Shift Arrow
sur un clavier ou même en tapant sur le curseur) et sera confus à propos de ce caractère étrange,placeholder
n'est plus affiché,clearButtonMode = .whileEditing
.Bien sûr, remplacer deleteBackward()
est un peu gênant en raison du besoin de sous-classement. Mais le meilleur UX en vaut la peine!
Et si le sous-classement est interdit, par exemple lors de l'utilisation de UISearchBar
avec son UITextField
intégré, le swizzling de la méthode devrait également convenir.
Si vous avez besoin de détecter le retour arrière, même dans textField vide (par exemple, si vous avez besoin de basculer automatiquement en arrière vers textField précédent en appuyant sur backSpace), vous pouvez utiliser une combinaison de méthodes proposées - ajouter un signe invisible et utiliser la méthode déléguée standard textField:shouldChangeCharactersInRange:replacementString:
comme suivre
Créer un signe invisible
private struct Constants {
static let InvisibleSign = "\u{200B}"
}
Définir le délégué pour textField
textField.delegate = self
Lors de l'événement EditingChanged
vérifiez le texte et si nécessaire ajoutez un symbole invisible comme suit:
@IBAction func didChangeEditingInTextField(sender: UITextField) {
if var text = sender.text {
if text.characters.count == 1 && text != Constants.InvisibleSign {
text = Constants.InvisibleSign.stringByAppendingString(text)
sender.text = text
}
}
}
Ajouter l'implémentation de la méthode déléguée textField:shouldChangeCharactersInRange:replacementString:
extension UIViewController : UITextFieldDelegate {
// MARK: - UITextFieldDelegate
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let char = string.cStringUsingEncoding(NSUTF8StringEncoding)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
if var string = textField.text {
string = string.stringByReplacingOccurrencesOfString(Constants.InvisibleSign, withString: "")
if string.characters.count == 1 {
//last visible character, if needed u can skip replacement and detect once even in empty text field
//for example u can switch to prev textField
//do stuff here
}
}
}
return true
}
}
Essaye ça
public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if(string == "") {
print("Backspace pressed");
return true;
}
}
Remarque: Vous pouvez retourner "true" si vous souhaitez autoriser le retour arrière. Sinon, vous pouvez retourner "false".
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let char = string.cString(using: String.Encoding.utf8)!
let isBackSpace = strcmp(char, "\\b")
if isBackSpace == -92 {
print("Backspace was pressed")
return false
}
}
Je trouve la comparaison utilisant strcmp
non pertinente. Nous ne savons même pas comment strcmp
fonctionne derrière les hottes. Dans toutes les autres réponses en comparant les caractères actuels et \b
, Les résultats sont -8
Dans l'objectif-C et -92
Dans Swift. J'ai écrit cette réponse parce que les solutions ci-dessus ne fonctionnaient pas pour moi. (Version Xcode 9.3 (9E145)
en utilisant Swift 4.1
)
FYI: Chaque caractère que vous tapez réellement est un tableau de 1
Ou plusieurs éléments dans utf8 Encoding
. Le caractère backSpace est [0]
. Vous pouvez l'essayer.
PS: N'oubliez pas d'assigner le bon delegates
à votre textFields
.
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let char = string.cString(using: String.Encoding.utf8)!
if (char.elementsEqual([0])) {
print("Backspace was pressed")
}
else {
print("WHAT DOES THE FOX SAY ?\n")
print(char)
}
return true
}
S'il vous plaît ne jetez pas votre code. Mettez simplement cette extension quelque part dans votre code. (Swift 4.1)
extension String {
var isBackspace: Bool {
let char = self.cString(using: String.Encoding.utf8)!
return strcmp(char, "\\b") == -92
}
}
Et puis il suffit de l'utiliser dans vos fonctions
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.isBackspace {
// do something
}
return true
}
J'ai implémenté cette fonctionnalité:
Et dans le cas où le dernier textFiled est vide, je veux juste passer au textFiled précédent. J'ai essayé toutes les réponses ci-dessus, mais personne ne fonctionne bien dans ma situation. Pour une raison quelconque, si j'ajoute plus de logique que print
dans isBackSpace == -92
les parenthèses bloquent cette méthode qui vient d'arrêter le travail ...
Quant à moi, la méthode ci-dessous est plus élégante et fonctionne comme un charme:
Rapide
class YourTextField: UITextField {
// MARK: Life cycle
override func awakeFromNib() {
super.awakeFromNib()
}
// MARK: Methods
override func deleteBackward() {
super.deleteBackward()
print("deleteBackward")
}
}
Merci @LombaX pour le réponse
Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//MARK:- If Delete button click
let char = string.cString(using: String.Encoding.utf8)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
return true
}
}
Swift 4: Si l'utilisateur appuie sur le bouton de retour arrière, la chaîne est vide, de sorte que cette approche force textField à n'accepter que les caractères d'un jeu de caractères spécifié (dans ce cas, les caractères utf8) et les espaces arrière (string.isEmpty case) .
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.cString(using: String.Encoding.utf8) != nil {
return true
} else if string.isEmpty {
return true
} else {
return false
}
}