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

你能帮帮我吗?

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

#EDIT 1

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

提前致谢。

【问题讨论】:

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

标签: ios objective-c xcode uitextfield placeholder


【解决方案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?

      【讨论】:

      • 好的。我会尝试,但我想替换占位符的单个文本。您可以看到当我们输入任何输入字符时,完整的占位符字符串已经消失了。我想覆盖它的默认行为。
      • 好的,我正在做一个演示,请稍候,如果可以的话,我会回复你。
      猜你喜欢
      • 2018-10-08
      • 2017-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-25
      • 2016-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多