如何实现占位符文本在 UITextField 中逐个字符消失

Posted

技术标签:

【中文标题】如何实现占位符文本在 UITextField 中逐个字符消失【英文标题】:How to achieve that placeholder text disappears character by character in UITextField 【发布时间】:2018-02-13 09:00:41 【问题描述】:

你能帮帮我吗?

UITextField 中,当我们提供占位符文本时,当我们输入任何字符时,其占位符字符串将消失。如何实现仅输入的字符将消失而不是完整的字符串?这意味着如果我输入 3 个字符,则只有占位符的前 3 个字符会消失。

#EDIT 1

另外,新输入的字符文本颜色会改变,其他剩余字符文本颜色保持不变。

提前致谢。

【问题讨论】:

不需要占位符,创建覆盖并设置文本文件的相同边界,基于它自动隐藏的文本字段字符 Ya ... 这是一个技巧,但我想通过覆盖默认占位符属性来实现使用代码。谢谢。 @Anbu.Karthik 实际上,您的解决方案不起作用当我想用特定字符(如 'A' 或 '10' 替换 '_' 下划线时,字符串中存在不匹配。跨度> 我猜你必须用覆盖来做到这一点。 @Anbu.Karthik 是真的。 _(下划线)你需要根据输入字符串计算用户给定的输入 【参考方案1】:

我不相信占位符的默认行为是可编辑的,但是您可以使用NSAttributedString 模拟占位符值来完成您想要完成的工作。

我确信这可以进行优化,但在这里我创建了一个处理程序类,它充当给定UITextField 的委托,操纵用户输入的字符串以达到预期的效果。您使用所需的占位符字符串初始化处理程序,因此您可以使任何文本字段以这种方式工作。

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)
    

这是我初始化上述 gif 的一种方式:

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)
    

这可以扩展为在初始化时采用颜色参数、字体等,或者您可能会发现它更干净地继承UITextField 并使其成为自己的委托。我还没有真正测试过这个选择/删除/替换多个字符。

input 变量将返回用户在任何给定点输入的文本。此外,使用固定宽度的字体可以消除用户键入时的抖动并替换占位符文本。

【讨论】:

【参考方案2】:

不要使用占位符文本,而是在文本字段下方使用 UILabel 并为两者提供相同的字体样式。标签文本应该是 比如“- - - - -”

当用户开始在文本字段上输入时,在每个字符按下后给一个空格。

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

【讨论】:

好的。不错的解决方案,但我正在等待更多回复,但如果没有其他方法可以做到这一点。我会接受你的回答【参考方案3】:

我的解决方案是使用 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
最初将文本字段文本设置为掩码模板 然后当用户输入输入时 shouldChangeCharactersInRange 被调用,它做得很好

#编辑 1 还有一些我已经实现的代码将光标移动到下划线位置。如果有人需要帮助。请评论我会帮助你。

#编辑 2

使用这种方法我遇到的问题

无法更改单个文本颜色。 @"_" 下划线和输入字符的颜色相同。 如果用户不提供任何输入,那么我必须提供检查以将空白作为字符串发送。 跟踪单个输入。

谢谢, 仍在等待是否有任何其他使用占位符字符串的解决方法。

【讨论】:

请添加完整的程序。 (创建一个有名字的类并在代码中实现)。【参考方案4】:

我想这正是您正在寻找的。使用文本 _2_-__-__A(不是占位符文本)创建您的 UITextField 对象。然后,将其视图控制器用作委托,并将其添加到视图控制器:

-(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;

它应该按预期工作。

【讨论】:

【参考方案5】:

对于这种情况,请像下面这样快速使用属性字符串,

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)

【讨论】:

当我们输入任何输入时,attributePlacholderString 不会消失。【参考方案6】:

不,如果在 UITextfield 上创建自定义层后,您将无法执行此操作,您需要检查输入的字符是否与占位符字符串匹配,然后只会替换该字符。 另见Replacing character after each type in UITextField?

【讨论】:

好的。我会尝试,但我想替换占位符的单个文本。您可以看到当我们输入任何输入字符时,完整的占位符字符串已经消失了。我想覆盖它的默认行为。 好的,我正在做一个演示,请稍候,如果可以的话,我会回复你。

以上是关于如何实现占位符文本在 UITextField 中逐个字符消失的主要内容,如果未能解决你的问题,请参考以下文章

如何移动/动画 UITextField 占位符文本

如何调整 UITextField 占位符文本以适合 UITextField 宽度?

如何使用左侧的占位符和右侧的编辑文本创建 UITextField?

在 UITextField 占位符中输入文本时,应一次消失一个字母

如何在 UITextField 占位符字符之间添加空格?

UITextField 中占位符文本的默认颜色是啥?