【问题标题】:How to change letter spacing of UIButton in Swift?如何在 Swift 中更改 UIButton 的字母间距?
【发布时间】:2015-12-02 17:12:34
【问题描述】:

我找到了如何将字母间距设置为 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).

【问题讨论】:

  • 问题到底出在哪里?请发布不适合您的代码。
  • 已更新,让您查看损坏的代码。

标签: swift uibutton letter-spacing


【解决方案1】:

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)

【讨论】:

    【解决方案2】:
    1. NSAttributedString 设为您链接的问题中的样子
    2. 在您的UIButton 上致电setAttributedTitle(_ ,forState:)

    试试这个(未经测试):

    let title = agreementButton.titleForState(.Normal)
    let attributedTitle = NSAttributedString(string: title, attributes: [NSKernAttributeName: 1.0])
    agreementButton.setAttributedTitle(attributedTitle, forState: .Normal)
    

    【讨论】:

    • 我的错。应该只是setAttributedTitle。已编辑
    【解决方案3】:

    斯威夫特 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)
    

    【讨论】:

    • 效果很好! “NSAttributedStringKey”现在应该是“NSAttributedString.Key”。
    【解决方案4】:

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

    GOTCHA:应用字符间距还会将空格添加到文本的 END。此错误功能/错误意味着居中对齐的文本将无法正确显示。

    修复:为属性文本创建 Range 时,从 text.count 值中减去 1(因此忽略字符串中的最后一个字符以实现间距。)

    例如由于额外的空间导致不正确的居中:

    固定:

    [编辑]

    在相关说明中,如果您使用 EdgeInsets 在文本周围施加填充,您的 UIButton 子类将需要覆盖 intrinsicContentsSize:

    override open var intrinsicContentSize: CGSize {
        let size = super.intrinsicContentSize
        let insets = self.titleEdgeInsets
        let width = size.width + insets.left + insets.right
        let height = size.height + insets.top + insets.bottom
        return CGSize(width: width, height: height)
    }
    

    【讨论】:

      【解决方案5】:

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

      用法:可以在storyboard上设置字母间距,也可以通过代码设置。

      button.letterSpacing = 2.0
      

      【讨论】:

        【解决方案6】:

        Code Different 的解决方案不尊重文本颜色设置。也可以覆盖 UIButton 类以使间距参数即使在情节提要中也可用。这是一个更新的 Swift 3 解决方案:

        斯威夫特 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_()
                }
            }
        }
        

        【讨论】:

          【解决方案7】:

          根据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
              }
          }
          

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              【解决方案9】:

              斯威夫特 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)
              

              【讨论】:

                猜你喜欢
                • 2014-12-06
                • 2011-07-05
                • 2016-10-07
                • 1970-01-01
                • 1970-01-01
                • 2011-12-11
                • 1970-01-01
                相关资源
                最近更新 更多