简体   繁体   English

如何设置 UITextField 的字母间距

[英]How to set letter spacing of UITextField

I have an app in which the user has to type a four digit pin code.我有一个应用程序,用户必须在其中键入一个四位数的密码。 All digits have to be at a set distance from each other.所有数字必须彼此保持一定距离。

Is there a way to do this if the PinTextField is a subclass of UIView ?如果PinTextFieldUIView的子类,有没有办法做到这一点? I know in a ViewController you could use UITextFieldTextDidChangeNotification and set the attributed text for each change.我知道在ViewController您可以使用UITextFieldTextDidChangeNotification并为每个更改设置属性文本。 Notifications don't seem to work in a UIView though.通知似乎在UIView不起作用。

Also I was wondering if there isn't a simpler way than making an attributed string for every update if you want to set the letter spacing of a UITextField text ?另外,我想知道如果要设置UITextField文本的字母间距,是否没有比为每次更新制作属性字符串更简单的方法?

Correct spacing:正确间距:

具有正确间距的 TextField

Wrong spacing:错误的间距:

间距错误的文本字段

No need to go for attributedText , which to be honest, was a mess implementing with modified spacing.不需要去attributedText ,老实说,用修改后的间距实现是一团糟。 As soon as I closed the keyboard the spacing disappeared, which prompted me to dig further.我一合上键盘,间距就消失了,这促使我进一步挖掘。

Every UITextField has a property called defaultTextAttributes , which according to Apple "returns a dictionary of text attributes with default values."每个 UITextField 都有一个名为defaultTextAttributes的属性,根据 Apple 的说法,它“返回具有默认值的文本属性字典”。 . . The Apple document also says that "this property applies the specified attributes to the entire text of the text field" Apple 文档还说“此属性将指定的属性应用于文本字段的整个文本”

Just find a suitable place in your code, usually where the textfield is being initialized and then copy and paste the following.只需在您的代码中找到合适的位置,通常是初始化文本字段的位置,然后复制并粘贴以下内容。

Answered in Swift 3.0在 Swift 3.0 中回答

textfield.defaultTextAttributes.updateValue(spacing, forKey: NSKernAttributeName)

where spacing is of CGFloat type.其中间距是 CGFloat 类型。 For example 2.0例如 2.0

This works for different fonts as well.这也适用于不同的字体。

Cheers!!干杯!!


The latest syntax seems to be:最新的语法似乎是:

 yourField.defaultTextAttributes.updateValue(36.0, 
     forKey: NSAttributedString.Key.kern)

This is what eventually worked to set the kern for every change这就是最终为每次更改设置字距的方法

    textField.addTarget(self, action: "textFieldDidChange", forControlEvents: .EditingChanged)

    func textFieldDidChange () {    
        let attributedString = NSMutableAttributedString(string: textField.text)
        attributedString.addAttribute(NSKernAttributeName, value: 5, range: NSMakeRange(0, count(textField.text)))
        attributedString.addAttribute(NSFontAttributeName, value: font, range: NSMakeRange(0, count(textField.text)))
        attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.blackColor(), range: NSMakeRange(0, count(textField.text)))

        textField.attributedText = attributedString
    }

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

        if count(textField.text) < 4 {
            return true
            // Else if 4 and delete is allowed
        }else if count(string) == 0 {
            return true
            // Else limit reached
        }else{
            return false
        }
    }

The problem however remains because different numbers have different widths, I will just resort back to making a UITextField for every digit.然而问题仍然存在,因为不同的数字具有不同的宽度,我将回到为每个数字制作一个UITextField

Use the defaultTextAttributes property of UITextField .使用UITextFielddefaultTextAttributes属性。 It will handle the conversion to NSAttributedString for you and apply the attributes you set.它将为您处理到NSAttributedString的转换并应用您设置的属性。 For example:例如:

    NSMutableDictionary *attrs = [self.textField.defaultTextAttributes mutableCopy];
[attrs addEntriesFromDictionary:@{
    NSKernAttributeName: @18,
    NSUnderlineColorAttributeName: [UIColor grayColor],
    NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle | NSUnderlinePatternDash)
}];
self.textField.defaultTextAttributes = attrs;

Not really sure about any other solution instead of using attributed string.不太确定任何其他解决方案,而不是使用属性字符串。

But for the notification part, you can set the textFields delegate to UIView and define below method in the view.但是对于通知部分,您可以将textFields委托设置为UIView并在视图中定义以下方法。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; 

The above method is called every time the text entered in the text field changes.每次在文本字段中输入的文本更改时都会调用上述方法。

Try this code After setting the delegate to the textfield.Hope it will work.在将委托设置为文本字段后试试这个代码。希望它会起作用。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:textField.text];
    [attributedString addAttribute:NSKernAttributeName
                             value:@(5.4)
                             range:NSMakeRange(0, textField.text.length)];
    textField.attributedText = attributedString;
    return YES;
}

This is working fine in Swift 2.2.这在 Swift 2.2 中运行良好。 Hope this will help you for letter spacing in text field希望这对您在文本字段中的字母间距有所帮助

override func viewDidLoad() {
 // Do any additional setup after loading the view.
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(SignupVC.limitTextField(_:)), name: "UITextFieldTextDidChangeNotification", object: txtContactNumber)
}
 func limitTextField(Notif:NSNotification) {

    let limit=10;

    let attributedString = NSMutableAttributedString(string: txtContactNumber.text!)
    attributedString.addAttribute(NSKernAttributeName, value: 7, range: NSMakeRange(0, (txtContactNumber.text?.characters.count)!))
   // attributedString.addAttribute(NSFontAttributeName, value: font, range: NSMakeRange(0, count(textField.text)))
    attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.blackColor(), range: NSMakeRange(0,(txtContactNumber.text?.characters.count)!))

    txtContactNumber.attributedText = attributedString
    if(txtContactNumber.text?.characters.count>limit)
    {
        txtContactNumber.text=txtContactNumber.text?.substringToIndex(limit)
    }
}

Need to count the kern for each character and remove it for the last character.需要计算每个字符的字距并将其删除为最后一个字符。 There is example on Swift 5.3 Swift 5.3 上有示例

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
    let maxLength = 6
    let symbolWidth = CGFloat(43)
    let font = UIFont.systemFont(ofSize: 30)
    
    if string == "" { // when user remove text
        return true
    }
        
    if textField.text!.count + string.count - range.length > maxLength { // when user type extra text
        return false
    }
    
    let currentText = NSMutableAttributedString(attributedString: textField.attributedText ?? NSMutableAttributedString())
    currentText.deleteCharacters(in: range) // delete selected text
    var newStringLength = 0 
    
    for char in string{
        let newSymbol = NSMutableAttributedString(string: String(char))
        newSymbol.addAttribute(.font, value: font, range: NSMakeRange(0, 1))
        let currentSymbolWidth = newSymbol.size().width
        let kern = symbolWidth - currentSymbolWidth
        newSymbol.addAttribute(.kern, value: kern, range: NSMakeRange(0,1))
        
        currentText.insert(newSymbol, at: range.location + newStringLength)
        newStringLength += 1
    }
    
    if currentText.length == maxLength{
        currentText.addAttribute(.kern, value: 0, range: NSMakeRange(maxLength - 1, 1))
    }
    
    textField.attributedText = currentText
    
    return false

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM