如何在UITextField中實現占位符文本逐字符消失

[英]How to achieve that placeholder text disappears character by character in UITextField


Can you please help me.

你能幫幫我嗎?

In UITextField when we provide a placeholder text its placeholder string will be gone when we enter any character. How can I achieve that only entered character will be gone not a full string? Meaning that if I type in 3 characters, only the first 3 characters of placeholder will be gone.

在UITextField中,當我們提供占位符文本時,當我們輸入任何字符時,它的占位符字符串都會消失。我怎么才能做到只有輸入字符才會變成一個完整的字符串?也就是說,如果我輸入3個字符,只有占位符的前3個字符將消失。

enter image description here

#EDIT 1

#編輯1

Also, newly entered character text color will change and other remaining character text color remains same.

另外,新輸入的字符文本顏色將會改變,其他字符文本顏色將保持不變。

Thanks in advance.

提前謝謝。

6 个解决方案

#1


3  

I don't believe the default behavior of the placeholder is editable, but what you are trying to accomplish can be done using NSAttributedString to simulate the placeholder value.

我不認為占位符的默認行為是可編輯的,但是可以使用NSAttributedString來模擬占位符值。

I'm sure this can be optimized, but here I have created a handler class that acts as the delegate for a given UITextField, manipulating the string the user inputs to achieve the desired effect. You init the handler with your desired placeholder string, so you can make any text field work this way.

我確信這是可以優化的,但這里我創建了一個處理程序類,它作為給定UITextField的委托,操作用戶輸入的字符串以實現所需的效果。你用你想要的占位符字符串初始化處理程序,所以你可以讓任何文本字段以這種方式工作。

Custom Placeholder Text Field

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)
    }
}

Here's a the way I initialized the gif above:

下面是我初始化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)
    }
}

This could be expanded to take color parameters, fonts, etc. at initialization, or you may find it cleaner to subclass UITextField and make it its own delegate. I also haven't really tested this for selecting/deleting/replacing multiple characters.

這可以擴展為在初始化時獲取顏色參數、字體等,或者您可能會發現它更適合UITextField的子類,並使其成為自己的委托。我也沒有真正地測試過選擇/刪除/替換多個字符。

The input variable will return the text the user has input at any given point. Also, using a fixed-width font would remove the jitteriness as the user types and replaces the placeholder text.

輸入變量將返回用戶在任何給定點上輸入的文本。此外,使用固定寬度的字體可以消除用戶輸入時的抖動,並替換占位符文本。

#2


3  

Instead of using placeholder text, use a UILabel below your textfield and give the same font style to both. the label text should be like "- - - - -"

與其使用占位符文本,不如在textfield下面使用UILabel,並為兩者提供相同的字體樣式。標簽文本應該是“- - - - - - - - -”

And when user starts typing on textfield give a space after each character press.

當用戶開始在textfield上打字時,在每個字符按下后給一個空格。

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


2  

There is my solution using UITextField text property

有一個使用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
  • Initially set text field text to mask template
  • 首先將文本字段文本設置為mask模板
  • Then when user enters input shouldChangeCharactersInRange invoked and it does a great job
  • 然后當用戶輸入shouldChangeCharactersInRange調用時,它會做得很好

#Edit 1 There is also some more code I have implemented which move the cursor to the underscore location. If someone need help. Please comment I will help you.

#Edit 1我還實現了一些代碼,可以將光標移動到下划線位置。如果有人需要幫助。請評論我將幫助你。

#Edit 2

#編輯2

Problems I have facing using this approached

我面對的問題已經接近了。

  • Not able to change individual text color. The color will be same for both the string like @"_" underscore and input characters has the same color.
  • 不能更改單獨的文本顏色。這兩個字符串的顏色相同,比如@“_”下划線和輸入字符的顏色相同。
  • If user not providing any input then I have to provide a check to send blank as a string.
  • 如果用戶不提供任何輸入,那么我必須提供一個支票以作為字符串發送空白。
  • Tracking for individual inputs.
  • 跟蹤單個輸入。

Thanks, Still waiting for if there is any other workaround using Placeholder String.

謝謝,還在等待是否有其他使用占位符字符串的方法。

#4


1  

I guess this is just what you are looking for. Create your UITextField object with the text _2_-__-__A (not placeholder text). Then, use its view controller as delegate, and add that to the view controller:

我猜這正是你要找的。使用文本_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;
}

It should work as intended.

它應該像預期的那樣工作。

#5


-1  

For that situation use attributed string in swift like bellow,

在這種情況下,使用帶屬性的字符串,

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)

#6


-3  

No You can not do this without make a custom layer on UITextfield after making it you need to check char entered does matched in placehoder string ,then only that charecter ll be replaced. see also Replacing character after each type in UITextField?

不,在UITextfield上創建自定義層之后,您就不能這樣做了,您需要檢查輸入的char是否與占位符字符串匹配,然后只替換那個charecter。還看到在UITextField中替換每個類型的字符嗎?


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2017/09/05/6784b4f3b2f25f875e2b9d11e6af188e.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com