ios - swift 4 change placeholder text color
Cómo lograr que el texto del marcador de posición desaparezca carácter por carácter en UITextField (6)
Podrías ayudarme.
En UITextField
cuando proporcionamos un texto de marcador de posición, su cadena de marcador de posición desaparecerá cuando UITextField
cualquier carácter. ¿Cómo puedo lograr que solo el carácter ingresado se haya ido, no una cadena completa? Lo que significa que si escribo 3 caracteres, solo desaparecerán los primeros 3 caracteres del marcador de posición.
#EDIT 1
Además, el color del texto del carácter recién introducido cambiará y el color del texto del otro carácter restante seguirá siendo el mismo.
Gracias por adelantado.
En lugar de usar texto de marcador de posición, use una etiqueta UIL debajo de su campo de texto y asigne el mismo estilo de fuente a ambos. el texto de la etiqueta debe ser como "- - - - -"
Y cuando el usuario comienza a escribir en el campo de texto, asigne un espacio después de 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
}
Hay mi solución usando la propiedad de texto 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 establece el texto del campo de texto para enmascarar la plantilla.
- Luego, cuando el usuario ingresa la entrada, debe invocarChangeCharactersInRange y hace un gran trabajo
#Edit 1 También he implementado un código más que mueve el cursor a la ubicación del subrayado. Si alguien necesita ayuda. Por favor comenta que te ayudaré.
#Editar 2
Problemas con los que me enfrento usando este acercado
- No se puede cambiar el color del texto individual. El color será el mismo para el guión bajo "@" y los caracteres de entrada tienen el mismo color.
- Si el usuario no proporciona ninguna entrada, tengo que proporcionar una verificación para enviar en blanco como una cadena.
- Seguimiento de entradas individuales.
Gracias, Todavía estoy esperando si hay alguna otra solución utilizando la Cadena de marcador de posición.
No creo que el comportamiento predeterminado del marcador de posición sea editable, pero lo que está intentando lograr se puede hacer usando NSAttributedString
para simular el valor del marcador de posición.
Estoy seguro de que esto se puede optimizar, pero aquí he creado una clase de manejador que actúa como delegado para un determinado UITextField
, manipulando la cadena que el usuario UITextField
para lograr el efecto deseado. Inicia el controlador con la cadena de marcador de posición deseada, de modo que puede hacer que cualquier campo de texto funcione de esta manera.
import UIKit
class CustomPlaceholderTextFieldHandler: NSObject {
let placeholderText: String
let placeholderAttributes = [NSForegroundColorAttributeName : UIColor.lightGray]
let inputAttributes = [NSForegroundColorAttributeName : UIColor(red: 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)
}
}
Esta es la forma en que inicialicé el gif de arriba:
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 se puede expandir para tomar parámetros de color, fuentes, etc. en la inicialización, o puede que le resulte más UITextField
subclasificar a UITextField
y convertirlo en su propio delegado. Tampoco lo he probado para seleccionar / eliminar / reemplazar varios caracteres.
La variable de input
devolverá el texto que el usuario haya ingresado en cualquier punto dado. Además, usar una fuente de ancho fijo eliminaría la inquietud a medida que el usuario escribe y reemplaza el texto del marcador de posición.
No, no puede hacer esto sin crear una capa personalizada en el campo de la UIT después de hacer que necesite verificar que el carácter ingresado coincida en la cadena de posicionador, entonces solo se reemplazará ese carácter. Consulte también ¿ Reemplazando el carácter después de cada tipo en UITextField?
Para esa situación, use la cadena atribuida en swift 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)
Supongo que esto es justo lo que estás buscando. Cree su objeto UITextField
con el texto _2_-__-__A
(no texto de marcador de posición). Luego, use su controlador de vista como delegado, y agregue eso al controlador 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.