如何在Swift中更改UIButton的字母间距?

时间:2015-12-02 17:12:34

标签: swift uibutton letter-spacing

我已经找到了如何将字母间距设置为UILabel(here),但此方法不适用于UIButtons。有谁知道怎么做?

这是我正在使用的代码

    let buttonString = agreementButton.attributedTitleForState(.Normal) as! NSMutableAttributedString
    buttonString.addAttribute(NSKernAttributeName, value: 1.0, range: NSMakeRange(0, buttonString.length))
    agreementButton.setAttributedTitle(buttonString, forState: .Normal)

它给我一个错误:'NSConcreteAttributedString' (0x19e508660) to 'NSMutableAttributedString' (0x19e506a40).

9 个答案:

答案 0 :(得分:12)

Swift 3.0

extension UIButton{
   func addTextSpacing(spacing: CGFloat){
       let attributedString = NSMutableAttributedString(string: (self.titleLabel?.text!)!)
       attributedString.addAttribute(NSKernAttributeName, value: spacing, range: NSRange(location: 0, length: (self.titleLabel?.text!.characters.count)!))
       self.setAttributedTitle(attributedString, for: .normal)
   }
}
btnRegister.addTextSpacing(spacing: 4.5)

extension UILabel{
    func addTextSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.text!)
        attributedString.addAttribute(NSKernAttributeName, value: spacing, range: NSRange(location: 0, length: self.text!.characters.count))
        self.attributedText = attributedString
    }
}
lblOne.addTextSpacing(spacing: 4.5)

extension UITextField{
    func addPlaceholderSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.placeholder!)
        attributedString.addAttribute(NSKernAttributeName, value: spacing, range: NSRange(location: 0, length: self.placeholder!.characters.count))
        self.attributedPlaceholder = attributedString
    }
}
txtUserName.addPlaceholderSpacing(spacing: 4.5)

extension UINavigationItem{
    func addSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.title!)
        attributedString.addAttribute(NSKernAttributeName, value: spacing, range: NSRange(location: 0, length: self.title!.characters.count))
        let label = UILabel()
        label.textColor = UIColor.black
        label.font = UIFont.systemFont(ofSize: 15, weight: UIFontWeightBold)
        label.attributedText = attributedString
        label.sizeToFit()
        self.titleView = label
    }
}
navigationItem.addSpacing(spacing: 2.5)

答案 1 :(得分:11)

  1. 在您关联的问题中设置2015-12-27
  2. 致电NSAttributedString
  3. 上的setAttributedTitle(_ ,forState:)

    试试这个(未经测试):

    UIButton

答案 2 :(得分:5)

快捷键4

extension UIButton{

    func addTextSpacing(_ letterSpacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: (self.titleLabel?.text!)!)
        attributedString.addAttribute(NSAttributedString.Key.kern, value: letterSpacing, range: NSRange(location: 0, length: (self.titleLabel?.text!.count)!))
        self.setAttributedTitle(attributedString, for: .normal)
    }

}

// Usage: button.addTextSpacing(5.0)

答案 3 :(得分:1)

来自Code Different的解决方案不尊重文字颜色设置。还可以覆盖UIButton类,即使在故事板中也可以使用spacing参数。这是一个更新的Swift 3解决方案:

Swift 3

class UIButtonWithSpacing : UIButton
{
    override func setTitle(_ title: String?, for state: UIControlState)
    {
        if let title = title, spacing != 0
        {
            let color = super.titleColor(for: state) ?? UIColor.black
            let attributedTitle = NSAttributedString(
                string: title,
                attributes: [NSKernAttributeName: spacing,
                             NSForegroundColorAttributeName: color])
            super.setAttributedTitle(attributedTitle, for: state)
        }
        else
        {
            super.setTitle(title, for: state)
        }
    }

    fileprivate func updateTitleLabel_()
    {
        let states:[UIControlState] = [.normal, .highlighted, .selected, .disabled]
        for state in states
        {
            let currentText = super.title(for: state)
            self.setTitle(currentText, for: state)
        }
    }

    @IBInspectable var spacing:CGFloat = 0 {
        didSet {
            updateTitleLabel_()
        }
    }
}

答案 4 :(得分:1)

不是一个完整的答案,而是一个GOTCHA和一个FIX。

GOTCHA:应用字符间距还会在文本的末尾添加空格。此功能失常/错误意味着居中对齐的文本将显示不正确。

FIX:在为属性文本创建范围时,请从text.count值中减去1(因此,出于间距目的,将忽略字符串中的最后一个字符)。

例如由于多余的空间导致居中错误:

enter image description here

已修复:

enter image description here

另一个问题是,设置任何文本都会清除所有NSAttributedString设置。因此,如果您更新标签,则必须记住还要再次应用字符间距。

作为一种解决方法,可以将characterSpacing属性添加到UIButton子类中,并覆盖setTitle(: for state:),以便每当调用setTitle(::)时,都可以设置{{ 1}}属性。

示例:(快速5)

characterSpacing

//在您的extension UIButton { /// Adds character spacing to the button's text label, as an /// AttributedString. /// /// Important: setting the text property of a UILabel on a UIButton will /// wipe away the character spacing. So, this must be called after you /// set the text. func setCharacterSpacing(_ spacing: CGFloat) { guard let label = self.titleLabel else { return } guard let text = label.text else { return } let attrStr = NSMutableAttributedString(string: text) // IMPORTANT. We do not want to apply the character spacing to the last // character in the string. let numChars = text.count - 1 guard numChars > 0 else { return } let range = NSRange(location: 0, length: numChars) attrStr.addAttribute(.kern, value: spacing, range: range) self.setAttributedTitle(attrStr, for: UIControl.State()) } } 子类中:

UIButton

如果您使用EdgeInsets在文本周围加上填充,则您的/// Custom character spacing. /// Returns nil if a custom character spacing is not set. var characterSpacing: CGFloat? { didSet { if let spacing = self.characterSpacing { self.setCharacterSpacing(spacing) } else { // Remove any custom character spacing by simply // setting the titleLabel again. // IMPORTANT: must use the super to this, not // our override, else we'll get in to an endless loop. let currentText = self.titleLabel?.text super.setTitle(currentText, for: UIControl.State()) } } } override func setTitle(_ title: String?, for state: UIControl.State) { super.setTitle(title, for: state) // Force an updating of any character spacing. let existingSpacing = self.characterSpacing self.characterSpacing = existingSpacing } 子类将需要覆盖UIButton

intrinsicContentsSize:

答案 5 :(得分:1)

Swift 5 扩展程序转到此处。

extension UIButton {
    @IBInspectable
    var letterSpacing: CGFloat {
        set {
            let attributedString: NSMutableAttributedString
            if let currentAttrString = attributedTitle(for: .normal) {
                attributedString = NSMutableAttributedString(attributedString: currentAttrString)
            }
            else {
                attributedString = NSMutableAttributedString(string: self.title(for: .normal) ?? "")
                setTitle(.none, for: .normal)
            }

            attributedString.addAttribute(NSAttributedString.Key.kern, value: newValue, range: NSRange(location: 0, length: attributedString.length))
            setAttributedTitle(attributedString, for: .normal)
        }
        get {
            if let currentLetterSpace = attributedTitle(for: .normal)?.attribute(NSAttributedString.Key.kern, at: 0, effectiveRange: .none) as? CGFloat {
                return currentLetterSpace
            }
            else {
                return 0
            }
        }
    }
}

用法:您可以在情节提要上或通过代码设置字母空间。

button.letterSpacing = 2.0

答案 6 :(得分:0)

根据jaya raj的答案更新 Swift 4

extension UIButton{
    func addTextSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: (self.titleLabel?.text!)!)
        attributedString.addAttribute(NSAttributedStringKey.kern, value: spacing, range: NSRange(location: 0, length: (self.titleLabel?.text!.characters.count)!))
        self.setAttributedTitle(attributedString, for: .normal)
    }
}

extension UILabel{
    func addTextSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.text!)
        attributedString.addAttribute(NSAttributedStringKey.kern, value: spacing, range: NSRange(location: 0, length: self.text!.characters.count))
        self.attributedText = attributedString
    }
}

extension UITextField{
    func addPlaceholderSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.placeholder!)
        attributedString.addAttribute(NSAttributedStringKey.kern, value: spacing, range: NSRange(location: 0, length: self.placeholder!.characters.count))
        self.attributedPlaceholder = attributedString
    }
}

extension UINavigationItem{
    func addSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.title!)
        attributedString.addAttribute(NSAttributedStringKey.kern, value: spacing, range: NSRange(location: 0, length: self.title!.characters.count))
        let label = UILabel()
        label.textColor = UIColor.black
        label.font = UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.bold)
        label.attributedText = attributedString
        label.sizeToFit()
        self.titleView = label
    }
}

答案 7 :(得分:0)

更新 Swift 5 而无需强制展开:

我认为这是一个更好的解决方案,因为我们也可以满足按钮上的现有属性

func addTextSpacing(_ letterSpacing: CGFloat) {
    let attributedString = attributedTitle(for: .normal)?.mutableCopy() as? NSMutableAttributedString ??
        NSMutableAttributedString(string: title(for: .normal) ?? "")
    attributedString.addAttribute(NSAttributedString.Key.kern, value: letterSpacing,
                                  range: NSRange(location: 0, length: attributedString.string.count))
    self.setAttributedTitle(attributedString, for: .normal)
}

答案 8 :(得分:0)

斯威夫特 5

guard let buttonTitle = button.title(for: .normal) else { return }
    
    let attributedTitle = NSAttributedString(string: buttonTitle, attributes: [NSAttributedString.Key.kern: kernValue])
    button.setAttributedTitle(attributedTitle, for: .normal)