iphone - uitextfielddelegate
Detecta el retroceso en UITextField (23)
Swift 4:
Subclase UITextField
:
// MyTextField.swift
import UIKit
protocol MyTextFieldDelegate {
func textFieldDidDelete()
}
class MyTextField: UITextField {
var myDelegate: MyTextFieldDelegate?
override func deleteBackward() {
super.deleteBackward()
myDelegate?.textFieldDidDelete()
}
}
Implementación:
// ViewController.swift
import UIKit
class ViewController: UIViewController, MyTextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// initialize textField
let input = MyTextField(frame: CGRect(x: 50, y: 50, width: 150, height: 40))
// set viewController as "myDelegate"
input.myDelegate = self
// add textField to view
view.addSubview(input)
// focus the text field
input.becomeFirstResponder()
}
func textFieldDidDelete() {
print("delete")
}
}
C objetivo:
Subclase UITextField
:
//Header
//MyTextField.h
//create delegate protocol
@protocol MyTextFieldDelegate <NSObject>
@optional
- (void)textFieldDidDelete;
@end
@interface MyTextField : UITextField<UIKeyInput>
//create "myDelegate"
@property (nonatomic, assign) id<MyTextFieldDelegate> myDelegate;
@end
//Implementation
#import "MyTextField.h"
@implementation MyTextField
- (void)deleteBackward {
[super deleteBackward];
if ([_myDelegate respondsToSelector:@selector(textFieldDidDelete)]){
[_myDelegate textFieldDidDelete];
}
}
@end
Ahora simplemente agregue MyTextFieldDelegate a su UIViewController
y configure su UITextFields
myDelegate en self
:
//View Controller Header
#import "MyTextField.h"
//add "MyTextFieldDelegate" to you view controller
@interface ViewController : UIViewController <MyTextFieldDelegate>
@end
//View Controller Implementation
- (void)viewDidLoad {
//initialize your text field
MyTextField *input =
[[MyTextField alloc] initWithFrame:CGRectMake(0, 0, 70, 30)];
//set your view controller as "myDelegate"
input.myDelegate = self;
//add your text field to the view
[self.view addSubview:input];
}
//MyTextField Delegate
- (void)textFieldDidDelete {
NSLog(@"delete");
}
¿Hay alguna forma de detectar cuándo se presiona la tecla UITextField
/ Eliminar en el teclado del iPhone en un UITextField
que está vacío? Quiero saber cuándo se presiona Retroceso solo si el UITextField
está vacío.
Basado en la sugerencia de @Alex Reynolds en un comentario, agregué el siguiente código al crear mi campo de texto:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleTextFieldChanged:)
name:UITextFieldTextDidChangeNotification
object:searchTextField];
Se recibe esta notificación (se handleTextFieldChanged
función handleTextFieldChanged
), pero aún no cuando handleTextFieldChanged
la tecla Retroceso en un campo vacío. ¿Algunas ideas?
Parece haber cierta confusión en torno a esta pregunta. Deseo recibir una notificación cuando se presiona la tecla Retroceso . Eso es. Pero la solución también debe funcionar cuando el UITextField
ya está vacío.
:) solo por el título "Detectar retroceso", donde uso UIKeyboardTypeNumberPad
.
También encuentro la misma pregunta esta noche, y el siguiente es mi código para descubrirlo:
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
{
NSLog([NSString stringWithFormat:@"%d", [string length]]);
}
Porque con UIKeyboardTypeNumberPad
, el usuario solo puede ingresar Número o retroceso, por lo que cuando la longitud de la cadena es 0, debe ser la tecla de retroceso.
Espero que lo anterior te ayude.
Actualización: Vea la respuesta de JacobCaraballo para un ejemplo que anula -[UITextField deleteBackward]
.
Verifique UITextInput
, específicamente UIKeyInput
tiene un método delegate deleteBackward
que siempre se llama cuando se presiona la tecla delete. Si está haciendo algo simple, entonces puede considerar simplemente subclasificar UILabel
y hacerlo conforme al protocolo UIKeyInput
, como lo hacen SimpleTextInput y este ejemplo de UIKeyInput de iPhone . Nota: UITextInput
y sus parientes (incluida UIKeyInput
) solo están disponibles en iOS 3.2 y versiones posteriores.
Algo como esto:
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
{
if (![text hash] && ![textField.text length])
[self backspaceInEmptyTextField];
}
por supuesto, el hash es para una cadena de caracteres.
Código como el siguiente:
@interface MyTextField : UITextField
@end
@implementation MyTextField
- (void)deleteBackward
{
[super deleteBackward];
//At here, you can handle backspace key pressed event even the text field is empty
}
@end
Por último, olvide cambiar la propiedad de clase personalizada del campo de texto a "MyTextField"
El mejor uso que he encontrado para detectar el retroceso es detectar cuando el usuario ha retrocedido en un UITextField
vacío. Por ejemplo, si tiene destinatarios ''borboteados'' en la aplicación de correo, cuando UITextField
Retroceso en el UITextField
, selecciona el último destinatario UITextField
.
Esto se puede hacer de forma similar a la respuesta de Jacob Caraballo. Pero en la respuesta de Jacob, si el UITextField
tiene un carácter restante cuando UITextField
el retroceso, cuando se recibe el mensaje de delegado, el UITextField
ya estará vacío, por lo que está efectivamente detectando el backspace
en un campo de texto con un máximo de un carácter.
En realidad, si desea detectar el backspace
en un UITextField
con exactamente cero caracteres (vacíos), entonces debe enviar el mensaje al delegate
antes de la llamada a super deleteBackward
. Por ejemplo:
#import "MyTextField.h"
//Text field that detects when backspace is hit with empty text
@implementation MyTextField
#pragma mark - UIKeyInput protocol
-(void)deleteBackward
{
BOOL isTextFieldEmpty = (self.text.length == 0);
if (isTextFieldEmpty) {
if ([self.delegate
respondsToSelector:@selector(textFieldDidHitBackspaceWithEmptyText:)]) {
[self.delegate textFieldDidHitBackspaceWithEmptyText:self];
}
}
[super deleteBackward];
}
@end
La interfaz para dicho campo de texto se vería así:
@protocol MyTextFieldDelegate;
@interface MyTextField : UITextField
@property(nonatomic, weak) id<MyTextFieldDelegate> delegate;
@end
@protocol MyTextFieldDelegate <UITextFieldDelegate>
@optional
-(void)textFieldDidHitBackspaceWithEmptyText:(MyTextField *)textField;
@end
En UITextViewDelegate
:
- (BOOL) textView:(UITextView *)textView
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text
{
if(text isEqualToString:@"");
{
NSLog(@"press backspace.");
}
}
funciona bien para mi
actualización para chino simplificado pinyin y entrada de escritura china:
- (BOOL) textView:(UITextView *)textView
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text
{
if (range.length > 0 && [text isEqualToString:@""]) {
NSLog(@"press Backspace.");
}
return YES;
}
la base en el documento dice:
"Si el usuario presiona deleteKey
, la longitud del rango es 1 y un objeto de cadena vacío reemplaza ese único carácter".
En el archivo .h, agregue el delegado UIKeyInput
- (BOOL)keyboardInputShouldDelete:(UITextField *)textField {
if ([textField isEqual:_txtFirstDigit]) {
}else if([textField isEqual:_txtSecondDigit]) {
[_txtFirstDigit becomeFirstResponder];
}else if([textField isEqual:_txtThirdDigit]) {
[_txtSecondDigit becomeFirstResponder];
}else if([textField isEqual:_txtFourthDigit]) {
[_txtThirdDigit becomeFirstResponder];
}
return YES;
}
formato mejorado
En iOS 6, se llama al método deleteBackward en el UITextField cuando se presiona el retroceso, incluso cuando el campo está vacío. De modo que puede subclasificar UITextField y proporcionar su propia implementación de deleteBackward (invocando super''s también).
Todavía apoyo iOS 5, así que necesitaré una combinación de la respuesta de Andrew y esto.
En lugar de intentar preconfigurar lo que SERÁ en el campo de texto o descubrir qué carácter especial se ha ingresado en el método shouldChangeCharactersInRange
, sugeriría hacer lo siguiente:
[self performSelector:@selector(manageSearchResultsDisplay)
withObject:nil
afterDelay:0];
Esto le permite llamar a un método directamente después de que se complete la operación actual. Lo bueno de esto es que, para cuando se complete, el valor modificado ya estará en UITextField
. En ese punto, puede verificar su longitud y / o validar en función de lo que hay allí.
Esto puede ser una posibilidad remota, pero podría funcionar. Intente configurar el texto del campo de texto en un carácter de espacio de ancho cero. Cuando se presiona retroceso en un campo de texto que aparece vacío, en realidad eliminará su espacio. Entonces puedes reinsertar el espacio.
Puede no funcionar si el usuario logra mover el cursor a la izquierda del espacio.
He fundado otra manera más fácil que la solución de subclass
. Incluso es un poco extraño pero funciona bien.
- (BOOL)textView:(UITextView *)textView
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text
{
const char * _char = [text cStringUsingEncoding:NSUTF8StringEncoding];
int isBackSpace = strcmp(_char, "/b");
if (isBackSpace == -8) {
// is backspace
}
return YES;
}
Es un poco extraño que el resultado de la comparación sea -8. Tal vez me equivoque en algún punto de la C Programming
Pero es el trabajo correcto;)
He implementado la solución similar con mejoras menores que me dirá que si el campo de texto tiene algún valor mientras el usuario ha tocado el espacio de retroceso. Esto es útil para mi caso cuando solo debería centrarme en otro campo de texto si el campo de texto está vacío cuando se presiona la tecla retroceso.
protocol MyTextFieldDelegate : UITextFieldDelegate {
func textFieldDidDelete(textField: MyTextField, hasValue: Bool)
}
override func deleteBackward() {
let currentText = self.text ?? ""
super.deleteBackward()
let hasValue = currentText.isEmpty ? false : true
if let delegate = self.delegate as? MyTextFieldDelegate {
delegate.textFieldDidDelete(textField: self, hasValue: hasValue)
}
}
Implementación rápida:
import UIKit
protocol PinTexFieldDelegate : UITextFieldDelegate {
func didPressBackspace(textField : PinTextField)
}
class PinTextField: UITextField {
override func deleteBackward() {
super.deleteBackward()
// If conforming to our extension protocol
if let pinDelegate = self.delegate as? PinTexFieldDelegate {
pinDelegate.didPressBackspace(self)
}
}
}
La respuesta de Niklas Alvaeus me ayudó con un problema similar
Estaba limitando la entrada a un juego de caracteres específico, pero estaba ignorando los espacios vacíos. Así que lo range.length == 1
verificar range.length == 1
antes de recortar el NSString
. Si es cierto, simplemente devuelvo la cadena y no la recorto. Vea abajo
- (BOOL) textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
{
NSCharacterSet *nonNumberSet =
[[NSCharacterSet characterSetWithCharactersInString:@"0123456789."]
invertedSet];
if (range.length == 1) {
return string;
}
else {
return ([string stringByTrimmingCharactersInSet:nonNumberSet].length > 0);
}
}
Para los que tienen problemas con la respuesta de Jacob, implementé mi subclase de campo de texto de la siguiente manera y funciona muy bien.
#import <UIKit/UIKit.h>
@class HTTextField;
@protocol HTBackspaceDelegate <NSObject>
@optional
- (void)textFieldDidBackspace:(HTTextField*)textField;
@end
@interface HTTextField : UITextField<UIKeyInput>
@property (nonatomic, assign) id<HTBackspaceDelegate> backspaceDelegate;
@end
#import "HTTextField.h"
@implementation HTTextField
- (void)deleteBackward {
[super deleteBackward];
if ([self.backspaceDelegate respondsToSelector:@selector(textFieldDidBackspace:)]){
[self.backspaceDelegate textFieldDidBackspace:self];
}
}
- (BOOL)keyboardInputShouldDelete:(UITextField *)textField {
BOOL shouldDelete = YES;
if ([UITextField instancesRespondToSelector:_cmd]) {
BOOL (*keyboardInputShouldDelete)(id, SEL, UITextField *) = (BOOL (*)(id, SEL, UITextField *))[UITextField instanceMethodForSelector:_cmd];
if (keyboardInputShouldDelete) {
shouldDelete = keyboardInputShouldDelete(self, _cmd, textField);
}
}
if (![textField.text length] && [[[UIDevice currentDevice] systemVersion] intValue] >= 8) {
[self deleteBackward];
}
return shouldDelete;
}
@end
Para mantenerlo simple aquí, es la única condición que debe verificar
if (range.length==1)
Prueba el delegate
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
Luego, compruebe si range.length == 1
que parece ser el caso cuando se golpea el backspace
.
Sí, use el método a continuación para detectar el retroceso, cuando textField está vacío.
Necesita agregar UITextFieldDelegate
yourTextField.delegate = self (DEBE REQUERIRSE)
Rápido:
func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true }
C objetivo:
- (BOOL)keyboardInputShouldDelete:(UITextField *)textField { return YES; }
Subclases UITextField no funcionó para mí en iOS 8.3, nunca se invocó deleteBackward.
Aquí está la solución que utilicé, funciona en todas las versiones de iOS 8 y debería funcionar también en otras versiones de iOS
for textField in textFields {
textField.text = " "
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if string == "" && textField.text == " " {
// Do stuff here
return false
}
return true
}
Usando el método Delegado TextField:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
Agregue el siguiente código en el método anterior para detectar el evento de eliminación
if(textField == YourTextField)
{
if ([string length] == 0 && range.length > 0)
{
// Your Code after deletion of character
}
}
utilice el siguiente código que le ayudará a detectar la tecla de eliminación de teclado, incluso si el campo de texto está vacío.
C objetivo :
- (BOOL)keyboardInputShouldDelete:(UITextField *)textField { return YES; }
Swift:
func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true }
+ (BOOL)detectBackspaceOnly:(NSString *)string
{
for(int i=0 ; i<string.length ; i++){
unichar caract = [string characterAtIndex:i];
if(caract != '' '' && caract != ''/n'')
return NO;
}
return YES;
}