Comment détecter les modifications de texte dans un champ de texte? La méthode déléguée shouldChangeCharactersInRange
fonctionne pour quelque chose, mais elle ne répondait pas exactement à mes besoins. Puisque jusqu'à ce qu'il retourne YES, les textes textField ne sont pas disponibles pour les autres méthodes d'observation.
par exemple. dans mon code calculateAndUpdateTextFields
n'a pas reçu le texte mis à jour, l'utilisateur a tapé.
Est-ce un moyen d'obtenir quelque chose comme textChanged
Java gestionnaire d'événements.
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
{
if (textField.tag == kTextFieldTagSubtotal
|| textField.tag == kTextFieldTagSubtotalDecimal
|| textField.tag == kTextFieldTagShipping
|| textField.tag == kTextFieldTagShippingDecimal)
{
[self calculateAndUpdateTextFields];
}
return YES;
}
De manière correcte de changer le texte de uitextfield, rappeler :
J'attrape les caractères envoyés à un contrôle UITextField à peu près comme ceci:
// Add a "textFieldDidChange" notification method to the text field control.
En Objective-C:
[textField addTarget:self
action:@selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
En rapide:
textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
Ensuite, dans la méthode
textFieldDidChange
, vous pouvez examiner le contenu du champ textField et recharger la vue tabulaire si nécessaire.
Vous pouvez l'utiliser et mettre CalculateAndUpdateTextFields comme votre selector
.
La réponse de XenElement est parfaite.
Les opérations ci-dessus peuvent également être effectuées dans le générateur d'interface en cliquant avec le bouton droit de la souris sur UITextField et en faisant glisser l'événement d'envoi "Modification modifiée" vers votre unité de sous-classe.
pour définir l'écouteur d'événement:
[self.textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
réellement écouter:
- (void)textFieldDidChange:(UITextField *)textField {
NSLog(@"text changed: %@", textField.text);
}
Swift:
yourTextfield.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: .editingChanged)
Ensuite, implémentez la fonction de rappel:
@objc func textFieldDidChange(textField: UITextField){
print("Text changed")
}
Comme indiqué ici: événement de modification de texte UITextField , il semble que à partir d'iOS 6 (iOS 6.0 et 6.1 cochée) impossible de détecter complètement les changements dans les objets UITextField
simplement en observant le UITextFieldTextDidChangeNotification
.
Il semble que seules les modifications apportées directement par le clavier iOS intégré soient désormais suivies. Cela signifie que si vous modifiez votre objet UITextField
simplement en invoquant quelque chose comme ceci: myUITextField.text = @"any_text"
, vous ne serez pas averti du moindre changement.
Je ne sais pas si c'est un bug ou si c'est prévu. Cela ressemble à un bogue puisque je n’ai trouvé aucune explication raisonnable dans la documentation. Ceci est également indiqué ici: événement de modification de texte UITextField .
Ma "solution" consiste à poster une notification par moi-même pour chaque modification apportée à mon UITextField
(si cette modification est effectuée sans utiliser le clavier iOS intégré). Quelque chose comme ça:
myUITextField.text = @"I'm_updating_my_UITextField_directly_in_code";
NSNotification *myTextFieldUpdateNotification =
[NSNotification notificationWithName:UITextFieldTextDidChangeNotification
object:myUITextField];
[NSNotificationCenter.defaultCenter
postNotification:myTextFieldUpdateNotification];
De cette façon, vous êtes sûr à 100% que vous recevrez la même notification lorsque vous modifiez la propriété .text
de votre objet UITextField
, que vous le mettiez à jour "manuellement" dans votre code ou par le biais du programme intégré. dans le clavier iOS.
Étant donné qu'il ne s'agit pas d'un comportement documenté, il est important de noter que cette approche peut conduire à 2 notifications reçues pour le même changement dans votre objet UITextField
. En fonction de vos besoins (ce que vous faites réellement lorsque votre UITextField.text
change) cela pourrait être un inconvénient pour vous.
Une approche légèrement différente consisterait à publier une notification personnalisée (c'est-à-dire avec un nom personnalisé autre que UITextFieldTextDidChangeNotification
) si vous avez réellement besoin de savoir si la notification était la vôtre ou si elle a été faite par iOS.
EDIT:
Je viens de trouver une approche différente qui, à mon avis, pourrait être meilleure:
Ceci implique la fonctionnalité d'observation de la valeur clé (KVO) (-) de Objective-C ( http://developer.Apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueObserving/KeyValueObserving.html#//Apple_ref/doc/uid/10000177-BCICJDHA ).
En gros, vous vous enregistrez en tant qu'observateur d'une propriété et si cette propriété change, vous en êtes averti. Le "principe" est assez similaire au fonctionnement de NSNotificationCenter
, étant le principal avantage du fait que cette approche fonctionne automatiquement aussi à partir d'iOS 6 (sans aucun Tweak spécial comme avoir à poster des notifications manuellement).
Pour notre scénario UITextField
-, cela fonctionne parfaitement si vous ajoutez ce code à, par exemple, votre UIViewController
qui contient le champ de texte:
static void *myContext = &myContext;
- (void)viewDidLoad {
[super viewDidLoad];
//Observing changes to myUITextField.text:
[myUITextField addObserver:self forKeyPath:@"text"
options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld
context:myContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if(context == myContext) {
//Here you get notified every time myUITextField's "text" property is updated
NSLog(@"New value: %@ - Old value: %@",
[change objectForKey:NSKeyValueChangeNewKey],
[change objectForKey:NSKeyValueChangeOldKey]);
}
else
[super observeValueForKeyPath:keyPath ofObject:object
change:change context:context];
}
Crédit à cette réponse concernant la gestion de "contexte": https://stackoverflow.com/a/12097161/2078512
Remarque: on dirait que lorsque vous êtes en train de modifier un UITextField
avec le clavier iOS intégré, la propriété "text" du champ de texte n'est pas mise à jour. à chaque nouvelle lettre tapée/enlevée. Au lieu de cela, l'objet de champ de texte est mis à jour "dans son ensemble" après que vous avez quitté le statut de premier répondant du champ de texte.
Ici dans la version Swift pour la même chose.
textField.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
func textFieldDidChange(textField: UITextField) {
}
Merci
J'ai résolu le problème en changeant le comportement de shouldChangeChractersInRange. Si vous renvoyez NON, les modifications ne seront pas appliquées par iOS en interne, mais vous aurez la possibilité de les modifier manuellement et d'effectuer toute action après les modifications.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
//Replace the string manually in the textbox
textField.text = [textField.text stringByReplacingCharactersInRange:range withString:string];
//perform any logic here now that you are sure the textbox text has changed
[self didChangeTextInTextField:textField];
return NO; //this make iOS not to perform any action
}
Version Swift testée:
//Somewhere in your UIViewController, like viewDidLoad(){ ... }
self.textField.addTarget(
self,
action: #selector(SearchViewController.textFieldDidChange(_:)),
forControlEvents: UIControlEvents.EditingChanged
)
Paramètres expliqués:
self.textField //-> A UITextField defined somewhere in your UIViewController
self //-> UIViewController
.textFieldDidChange(_:) //-> Can be named anyway you like, as long as it is defined in your UIViewController
Ajoutez ensuite la méthode que vous avez créée ci-dessus dans votre UIViewController
:
//Gets called everytime the text changes in the textfield.
func textFieldDidChange(textField: UITextField){
print("Text changed: " + textField.text!)
}
Swift 4
func addNotificationObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidChangeAction(_:)), name: .UITextFieldTextDidChange, object: nil)
}
@objc func textFieldDidChangeAction(_ notification: NSNotification) {
let textField = notification.object as! UITextField
print(textField.text!)
}
Pour Swift 3.0:
let textField = UITextField()
textField.addTarget(
nil,
action: #selector(MyClass.textChanged(_:)),
for: UIControlEvents.editingChanged
)
en utilisant la classe comme:
class MyClass {
func textChanged(sender: Any!) {
}
}
Version Swift
yourTextField.addTarget(self, action: #selector(YourControllerName.textChanges(_:)), for: UIControlEvents.editingChanged)
Et obtenez les changements ici
func textChanges(_ textField: UITextField) {
let text = textField.text! // your desired text here
// Now do whatever you want.
}
J'espère que ça aide.
Vous devez utiliser la notification pour résoudre ce problème, car l’autre méthode écoute la zone de saisie et non l’entrée, en particulier lorsque vous utilisez la méthode de saisie en chinois. Dans viewDidload
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFiledEditChanged:)
name:@"UITextFieldTextDidChangeNotification"
object:youTarget];
ensuite
- (void)textFiledEditChanged:(NSNotification *)obj {
UITextField *textField = (UITextField *)obj.object;
NSString *toBestring = textField.text;
NSArray *currentar = [UITextInputMode activeInputModes];
UITextInputMode *currentMode = [currentar firstObject];
if ([currentMode.primaryLanguage isEqualToString:@"zh-Hans"]) {
UITextRange *selectedRange = [textField markedTextRange];
UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
if (!position) {
if (toBestring.length > kMaxLength)
textField.text = toBestring;
}
}
enfin, vous courez, allez faire.
Swift 3.1:
Sélecteur: ClassName.MethodName
cell.lblItem.addTarget(self, action: #selector(NewListScreen.fieldChanged(textfieldChange:)), for: .editingChanged)
func fieldChanged(textfieldChange: UITextField){
}
Avec fermeture:
class TextFieldWithClosure: UITextField {
var targetAction: (() -> Void)? {
didSet {
self.addTarget(self, action: #selector(self.targetSelector), for: .editingChanged)
}
}
func targetSelector() {
self.targetAction?()
}
}
et en utilisant
textField.targetAction? = {
// will fire on text changed
}
Swift 3 Version:
class SomeClass: UIViewController, UITextFieldDelegate {
@IBOutlet weak var aTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
aTextField.delegate = self
aTextField.addTarget(self, action: #selector(SignUpVC.textFieldDidChange), for: UIControlEvents.editingChanged)
}
func textFieldDidChange(_ textField: UITextField) {
//TEXT FIELD CHANGED..SECRET STUFF
}
}
N'oubliez pas de définir le délégué.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didChangeTextViewText:)
name:UITextFieldTextDidChangeNotification object:nil];
- (void) didChangeTextViewText {
//do something
}
Swift 4 Version
tilisation de l'observation de la valeur clé Informer les objets des modifications apportées aux propriétés d'autres objets.
var textFieldObserver: NSKeyValueObservation?
textFieldObserver = yourTextField.observe(\.text, options: [.new, .old]) { [weak self] (object, changeValue) in
guard let strongSelf = self else { return }
print(changeValue)
}