Cómo lograr ese text de marcador de position desaparece carácter por carácter en UITextField

Podrías ayudarme.

En UITextField cuando proporcionamos un text de marcador de position, su cadena de marcador de position desaparecerá cuando UITextField cualquier carácter. ¿Cómo puedo lograr que el único carácter ingresado se vaya no una cadena completa? Lo que significa que si escribo 3 caracteres, solo desaparecerán los primeros 3 caracteres del marcador de position.

introduzca la descripción de la imagen aquí

#EDIT 1

Además, el color del text del carácter recién ingresado cambiará y el rest del color del text del carácter sigue siendo el mismo.

Gracias por adelantado.

No creo que el comportamiento pnetworkingeterminado del marcador de position sea editable, pero lo que está tratando de lograr se puede hacer utilizando NSAttributedString para simular el valor del marcador de position.

Estoy seguro de que esto se puede optimizar, pero aquí he creado una class de controller que actúa como delegado para un determinado UITextField , manipulando la cadena que UITextField el usuario para lograr el efecto deseado. Inicia el controller con la cadena de marcador de position deseada, para que pueda hacer que cualquier campo de text funcione de esta manera.

Campo de texto de marcador de posición personalizado

 import UIKit class CustomPlaceholderTextFieldHandler: NSObject { let placeholderText: String let placeholderAttributes = [NSForegroundColorAttributeName : UIColor.lightGray] let inputAttributes = [NSForegroundColorAttributeName : UIColor(networking: 255/255, green: 153/255, blue: 0, alpha: 1.0)] var input = "" init(placeholder: String) { self.placeholderText = placeholder super.init() } func resetPlaceholder(for textField: UITextField) { input = "" setCombinedText(for: textField) } fileprivate func setCursorPosition(for textField: UITextField) { guard let cursorPosition = textField.position(from: textField.beginningOfDocument, offset: input.characters.count) else { return } textField.selectedTextRange = textField.textRange(from: cursorPosition, to: cursorPosition) } fileprivate func setCombinedText(for textField: UITextField) { let placeholderSubstring = placeholderText.substring(from: input.endIndex) let attributedString = NSMutableAttributedString(string: input + placeholderSubstring, attributes: placeholderAttributes) attributedString.addAttributes(inputAttributes, range: NSMakeRange(0, input.characters.count)) textField.attributedText = attributedString } } extension CustomPlaceholderTextFieldHandler: UITextFieldDelegate { func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if string == "" { if input.characters.count > 0 { input = input.substring(to: input.index(before: input.endIndex)) } } else { input += string } if input.characters.count <= placeholderText.characters.count { setCombinedText(for: textField) setCursorPosition(for: textField) return false } return true } func textFieldDidBeginEditing(_ textField: UITextField) { setCursorPosition(for: textField) } } 

Aquí hay una forma en que inicialicé el gif anterior:

 class ViewController: UIViewController { @IBOutlet weak var textField: UITextField! let placeholderHandler = CustomPlaceholderTextFieldHandler(placeholder: "_2_-__-__A") override func viewDidLoad() { super.viewDidLoad() textField.delegate = placeholderHandler placeholderHandler.resetPlaceholder(for: textField) } } 

Esto podría ampliarse para tomar parameters de color, fonts, etc. en la initialization, o puede ser más limpio para la subclass UITextField y convertirlo en su propio delegado. También realmente no he probado esto para seleccionar / eliminar / replace varios caracteres.

La variable de input devolverá el text que el usuario ha ingresado en cualquier punto dado. Además, el uso de una fuente de ancho fijo eliminaría la inquietud a medida que el usuario escribe y reemplaza el text del marcador de position.

En lugar de utilizar el text de marcador de position, use una UILabel debajo de su campo de text y otorgue el mismo estilo de fuente a ambos. el text de la label debe ser como "- – – – -"

Y cuando el usuario comienza a escribir en el campo de text, dé un espacio después de que cada carácter presione.

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if textField.text?.characters.count == 0 && string.characters.count != 0 { textField.text = textField.text! + " " } else { return false } if textField.text?.characters.count == 1 && string.characters.count != 0 { textField.text = textField.text! + " " } else { return false } if textField.text?.characters.count == 2 && string.characters.count != 0 { textField.text = textField.text! + " " } else { return false } if textField.text?.characters.count == 3 && string.characters.count != 0 { textField.text = textField.text! + " " } else { return false } return true } 

Existe mi solución usando la propiedad de text UITextField

 +(BOOL)shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string textField:(UITextField *)textField mask:(NSString *)mask withMaskTemplate:(NSString *)maskTemplate{ NSString * alreadyExistString = @""; if (string.length == 0) { alreadyExistString = textField.text; for (int i = range.location; i >= 0; i--) { unichar currentCharMask = [maskTemplate characterAtIndex:i]; unichar currentChar = [alreadyExistString characterAtIndex:i]; if (currentCharMask == currentChar) {// fixed value and _ continue; }else{ alreadyExistString = [alreadyExistString stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:@"_"]; break; } } textField.text = alreadyExistString; return NO; }else{ alreadyExistString = [textField.text stringByReplacingCharactersInRange:NSMakeRange(range.location, 1) withString:string]; } NSMutableString * validText = [[NSMutableString alloc] init]; int last = 0; BOOL append = NO; for (int i = 0; i < alreadyExistString.length; i++) { unichar currentCharMask = [mask characterAtIndex:i]; unichar currentChar = [alreadyExistString characterAtIndex:i]; BOOL isLetter = [[NSCharacterSet alphanumericCharacterSet] characterIsMember: currentChar]; BOOL isDigit = [[NSCharacterSet decimalDigitCharacterSet] characterIsMember: currentChar]; if ((isLetter && currentCharMask == '#') || (isDigit && currentCharMask == '9')) { [validText appendString:[NSString stringWithFormat:@"%c",currentChar]]; }else{ if (currentCharMask == '#' || currentCharMask == '9') { break; } if ((isLetter && currentCharMask!= currentChar)|| (isDigit && currentCharMask!= currentChar)) { append = YES; } [validText appendString:[NSString stringWithFormat:@"%c",currentCharMask]]; } last = i; } for (int i = last+1; i < mask.length; i++) { unichar currentCharMask = [mask characterAtIndex:i]; if (currentCharMask != '#' && currentCharMask != '9') { [validText appendString:[NSString stringWithFormat:@"%c",currentCharMask]]; } if (currentCharMask == '#' || currentCharMask == '9') { break; } } if (append) { [validText appendString:string]; } NSString *placeHolderMask = textField.text; NSString *sub = [validText substringWithRange:NSMakeRange(range.location, 1)]; placeHolderMask = [placeHolderMask stringByReplacingCharactersInRange:NSMakeRange(range.location, 1) withString:sub]; textField.text = placeHolderMask; return NO; } @property (nonatomic,strong) NSString * maskTemplate;// like: _2_-__-__A @property (nonatomic,strong) NSString * mask;// like: #2#-99-##A 
  • Inicialmente, establezca el text del campo de text para enmascarar la plantilla.
  • Luego, cuando el usuario ingresa la input shouldChangeCharactersInRange invocado y hace un excelente trabajo

#Edit 1 También hay un código más que he implementado que mueve el cursor a la location de guión bajo. Si alguien necesita ayuda. Por favor, comentario te ayudaré.

#Editar 2

Los problemas con los que me he enfrentado al usar este enfoque

  • No puede cambiar el color del text individual. El color será el mismo para la cadena como el subrayado @ "_" y los caracteres de input tienen el mismo color.
  • Si el usuario no proporciona ninguna input, entonces tengo que proporcionar un cheque para enviar en blanco como una cadena.
  • Seguimiento de inputs individuales.

Gracias, Aún esperando si hay alguna otra solución utilizando la Cadena de marcador de position.

Supongo que esto es justo lo que estás buscando. Cree su object UITextField con el text _2_-__-__A (no text de marcador de position). Luego, use su controller de vista como delegado y agregue eso al controller de vista:

 -(BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string{ if (range.length>1) return NO; // Avoids removing multiple characters at once if (range.location==1) range.location++; // '2' index if (range.location==3) range.location++; // '-' index if (range.location==6) range.location++; // '-' index if (range.location==9) return NO; // 'A' index if (range.location==10) return NO; // String end if ([string isEqualToString:@""]) return NO; //Avoids removing characters if (range.length==0) { range.length++; UITextPosition *beginning = textField.beginningOfDocument; UITextPosition *start = [textField positionFromPosition:beginning offset:range.location]; UITextPosition *end = [textField positionFromPosition:start offset:range.length]; UITextRange *textRange = [textField textRangeFromPosition:start toPosition:end]; [textField setSelectedTextRange:textRange]; } return YES; } -(void)textFieldDidBeginEditing:(UITextField*)textField{ UITextPosition *beginning = textField.beginningOfDocument; UITextPosition *start = [textField positionFromPosition:beginning offset:0]; UITextPosition *end = [textField positionFromPosition:start offset:0]; UITextRange *textRange = [textField textRangeFromPosition:start toPosition:end]; [textField setSelectedTextRange:textRange]; } -(BOOL)textFieldShouldReturn:(UITextField*)textField{ [passwordInput resignFirstResponder]; return YES; } 

Debería funcionar según lo previsto.

Para esa situación, use una cadena atribuida en forma rápida como abajo,

 let attributeFontSaySomething : [String : Any] = [NSFontAttributeName : UIFont.systemFont(ofSize: 12.0)] let attributeColorSaySomething : [String : Any] = [NSForegroundColorAttributeName : UIColor.blue] var attributes = attributeFontSaySomething for (key, value) in attributeColorSaySomething { attributes(value, forKey: key) } let attStringSaySomething = NSAttributedString(string: "Say something", attributes: attributes) 

No No puede hacer esto sin hacer una capa personalizada en UITextfield después de hacerlo, necesita verificar que el código entrado esté emparejado en la cadena placehoder, entonces solo se replaceá ese carácter. ver también Reemplazar carácter después de cada tipo en UITextField?