【问题标题】:Change character spacing on UILabel within Interface Builder在 Interface Builder 中更改 UILabel 上的字符间距
【发布时间】:2014-12-17 22:18:24
【问题描述】:

是否可以使用 Interface Builder 更改 UILabel 文本上的字符间距(轨道)?如果没有,有没有办法在已经使用属性文本创建的现有 UILabel 上以编程方式执行此操作?

【问题讨论】:

  • 我 99% 确定 Xcode 6 不支持这个。
  • @Drux 我 99% 确定 Xcode 6 可以做 IBDesignables

标签: ios swift uilabel interface-builder


【解决方案1】:

我知道这不是一个 Interface Builder 解决方案,但您可以创建一个 UILabel 扩展,然后为您想要的任何 UILabel 添加间距:

extension UILabel {
  func addCharacterSpacing(kernValue: Double = 1.15) {
    guard let text = text, !text.isEmpty else { return }
    let string = NSMutableAttributedString(string: text)
    string.addAttribute(NSAttributedString.Key.kern, value: kernValue, range: NSRange(location: 0, length: string.length - 1))
    attributedText = string
  }
}

考虑将默认的 kernValue1.15 更改为更适合您的设计的内容。


实现always时,在设置文本值后添加字符间距:

myLabel.text = "We used to be so close"
myLabel.addCharacterSpacing()

如果您打算在应用中的不同位置设置不同的间距,您可以覆盖默认的 kern 值:

myLabelWithSpecialNeeds.addCharacterSpacing(kernValue: 1.3)

此解决方案会覆盖您在 UILabelattributedText 上可能拥有的任何其他属性。

【讨论】:

  • 是否可以更改字符间距?
  • @Priyal,里面有一个 1.15 的间距值......如果你想要更多的间距,只需将其更改为更大的数字
  • @budidino 我可以从示例中推断出您增加了单词之间的间距,但我想更改字符间距,即。在 We & user 或 used & to.... 之间,但我想管理 We 的 'W' 和 'e'、用户的 'u'、's'、'e' 和 'r' 之间的间距。有可能吗?
  • @budidino 谢谢!是不是相当于缩小横向间距?
  • 非常好的答案!小补充:当字符串为“”(空)时,您可以将 if 子句更改为if let textString = text, textString.length > 0catch index out of bounds
【解决方案2】:

暂时使用它来获取现有的属性文本并修改以添加字符间距:

let attributedString = discoveryTitle.attributedText as NSMutableAttributedString
attributedString.addAttribute(NSKernAttributeName, value: 1.0, range: NSMakeRange(0, attributedString.length))
discoveryTitle.attributedText = attributedString

斯威夫特 3:

let attributedString = NSMutableAttributedString(string: discoveryTitle.text)
attributedString.addAttribute(NSKernAttributeName, value: CGFloat(1.0), range: NSRange(location: 0, length: attributedString.length))
discoveryTitle.attributedText = attributedString

使用 NSRange 代替 NSMakeRange 在 Swift 3 中有效。

【讨论】:

  • +1。很棒的答案。如果您的文本必须保持居中,则将字距应用于除最后一个字符之外的所有字符,即将NSMakeRange(0, attributedString.length) 更改为NSMakeRange(0, attributedString.length - 1)Source
  • @paulvs 是正确的。您还需要验证空字符串以避免崩溃。只需添加max(0, attributedString.length - 1) 即可。
【解决方案3】:

对于完全静态的文本,例如视图的标题或特别是 launchScreen,您可以插入占用很小宽度的字母(例如 'l ' 字符)与0 opacity。或者将其颜色设置为与背景相同。

我知道,这不是最漂亮的解决方案,但它是唯一无需编写任何代码即可工作并完成工作的解决方案 - 直到您可以通过在 Xcode 中指定属性来完成。

编辑/附加想法:要使您的间距更加可变,您可以更改填充字符的字体大小。 (感谢@mohamede1945 的想法)

【讨论】:

  • 很棒的解决方案! :) 您甚至可以使用“|”的字体大小来控制宽度特点。您所需要的只是创建一个并复制/粘贴它:)
  • @mohamede1945 好主意,在我真正阅读您的评论并再次通读我的答案之前(已经给出了很长一段时间)我也想到了可能更改字体大小的想法 - 然后阅读您的评论...如果两个人独立提出相同的想法,那一定很好;)
  • 嗨 Luk - 我真的爱你,但这确实是个坏主意。对不起,伙计!
  • 以本地化为例……它会搞砸的
  • 这对于可访问性来说是一个非常糟糕的主意。如果您使用它,请务必将可访问性标签设置为真实文本。
【解决方案4】:

Swift 3.2 和界面构建器

extension UILabel {

    @IBInspectable
    var letterSpace: CGFloat {
        set {
            let attributedString: NSMutableAttributedString!
            if let currentAttrString = attributedText {
                attributedString = NSMutableAttributedString(attributedString: currentAttrString)
            }
            else {
                attributedString = NSMutableAttributedString(string: text ?? "")
                text = nil
            }

            attributedString.addAttribute(NSKernAttributeName,
                                           value: newValue,
                                           range: NSRange(location: 0, length: attributedString.length))

            attributedText = attributedString
        }

        get {
            if let currentLetterSpace = attributedText?.attribute(NSKernAttributeName, at: 0, effectiveRange: .none) as? CGFloat {
                return currentLetterSpace
            }
            else {
                return 0
            }
        }
    }
}

【讨论】:

  • 完美运行。似乎我在我的代码中遗漏了一部分。对不起
  • 这个不支持自定义字体
  • 完全完美的方式。我还为 UILabel 和 UIButton 添加了相同的代码,它们也可以工作。只需从 UIButton 的 titleLabel.text 和 titleLabel.attributedText 获取文本
  • 很好的解决方案,在更高版本的 Xcode 中更新了一些代码更新,但 Xcode 会为您处理所有修复。谢谢!
【解决方案5】:

Swift 5 及更高版本

extension UILabel {
  func setTextSpacingBy(value: Double) {
    if let textString = self.text {
      let attributedString = NSMutableAttributedString(string: textString)
      attributedString.addAttribute(NSKernAttributeName, value: value, range: NSRange(location: 0, length: attributedString.length - 1))
      attributedText = attributedString
    }
  }
}

【讨论】:

  • @craft 他在没有默认值之前编辑了他的答案。我也会编辑我的,谢谢。
【解决方案6】:

试试这个!!

创建 CustomLabel 类

@interface CustomLabel : UILabel
@property (assign, nonatomic) CGFloat myLineSpacing;
@end


@implementation CustomLabel

- (void)setMyLineSpacing:(CGFloat)myLineSpacing {
    _myLineSpacing = myLineSpacing;
    self.text = self.text;
}

- (void)setText:(NSString *)text {
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.lineSpacing = _myLineSpacing;
    paragraphStyle.alignment = self.textAlignment;
    NSDictionary *attributes = @{NSParagraphStyleAttributeName: paragraphStyle};
    NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text
                                                                         attributes:attributes];
    self.attributedText = attributedText;
}

并设置运行时属性

注意这实际上是 行距(也称为 leading .. 在过去(数字化之前)你会说线之间的铅(金属)以增加线之间的间隙。对于字母之间的间距,这称为kerning ..这是如何进行kerning https://stackoverflow.com/a/21141156/294884

【讨论】:

  • 漂亮 - 你不会在这里使用 IBDesignables 吗?
  • 但这个问题是关于字母间距,而不是行间距
【解决方案7】:

为什么你们都在定义 NSMUTABLEAttributedString。您不必明确设置范围。它使表情符号有时看起来很奇怪。 这是我的解决方案,在 Swift 4 中进行了测试。 ?

extension UILabel {
    func addCharactersSpacing(_ value: CGFloat = 1.15) {
        if let textString = text {
            let attrs: [NSAttributedStringKey : Any] = [.kern: value]
            attributedText = NSAttributedString(string: textString, attributes: attrs)
        }
    }
}

【讨论】:

  • 如果您不指定范围,则居中和右对齐的文本将看起来不正确,因为在最后一个字符之后会添加间距。不过我可能完全错了:)
【解决方案8】:

SWIFT 4 UILabel 扩展:

import UIKit

extension UILabel {

    @IBInspectable
    var letterSpace: CGFloat {
        set {
            let attributedString: NSMutableAttributedString!
            if let currentAttrString = attributedText {
                attributedString = NSMutableAttributedString(attributedString: currentAttrString)
            } else {
                attributedString = NSMutableAttributedString(string: text ?? "")
                text = nil
            } 
            attributedString.addAttribute(NSAttributedString.Key.kern,
                                          value: newValue,
                                          range: NSRange(location: 0, length: attributedString.length))
            attributedText = attributedString
        }

        get {
            if let currentLetterSpace = attributedText?.attribute(NSAttributedString.Key.kern, at: 0, effectiveRange: .none) as? CGFloat {
                return currentLetterSpace
            } else {
                return 0
            }
        }
    }
}

【讨论】:

    【解决方案9】:

    这是一个不会覆盖现有文本属性的 Swift 4 解决方案:

    extension UILabel {
    
        /**
         Add kerning to a UILabel's existing `attributedText`
         - note: If `UILabel.attributedText` has not been set, the `UILabel.text`
         value will be returned from `attributedText` by default
         - note: This method must be called each time `UILabel.text` or
         `UILabel.attributedText` has been set
         - parameter kernValue: The value of the kerning to add
         */
        func addKern(_ kernValue: CGFloat) {
            guard let attributedText = attributedText,
                attributedText.string.count > 0,
                let fullRange = attributedText.string.range(of: attributedText.string) else {
                    return
            }
            let updatedText = NSMutableAttributedString(attributedString: attributedText)
            updatedText.addAttributes([
                .kern: kernValue
                ], range: NSRange(fullRange, in: attributedText.string))
            self.attributedText = updatedText
        }
    }
    

    【讨论】:

      【解决方案10】:

      您可以使用以下 Swift 4 UILabel 扩展,该扩展同时考虑现有的属性文本和纯文本,以免覆盖现有设置:

      import UIKit
      
      extension UILabel {
          func addCharacterSpacing(_ kernValue: Double = 1.30) {
              guard let attributedString: NSMutableAttributedString = {
                  if let text = self.text, !text.isEmpty {
                      return NSMutableAttributedString(string: text)
                  } else if let attributedText = self.attributedText {
                      return NSMutableAttributedString(attributedString: attributedText)
                  }
                  return nil
                  }() else { return}
      
              attributedString.addAttribute(
                  NSAttributedString.Key.kern,
                  value: kernValue,
                  range: NSRange(location: 0, length: attributedString.length)
              )
              self.attributedText = attributedString
          }
      }
      

      【讨论】:

        【解决方案11】:

        这是我的字母间距代码。创建自定义标签类并从情节提要中设置字母间距。斯威夫特 5。

        import UIKit
        
        class SpacingLabel: UILabel {
        
            @IBInspectable
            var letterSpacing: Double = 0
        
            override public var text: String? {
                didSet {
                    self.addCharacterSpacing(letterSpacing)
                }
            }
        
            func addCharacterSpacing(_ kernValue: Double) {
                if let labelText = text, labelText.count > 0 {
                    let attributedString = NSMutableAttributedString(string: labelText)
                    attributedString.addAttribute(NSAttributedString.Key.kern, value: kernValue, range: NSRange(location: 0, length: attributedString.length - 1))
                    attributedText = attributedString
                }
            }
        }
        

        【讨论】:

        • 请注意,您必须从代码中调用 label.text = "some text" 才能使其工作:))
        【解决方案12】:

        试试这个。它将添加您指定的字符间距,您可以设置简单文本或属性文本。

        open class UHBCustomLabel : UILabel {
            @IBInspectable open var characterSpacing:CGFloat = 1 {
                didSet {
                    updateWithSpacing()
                }
        
            }
        
            open override var text: String? {
                set {
                    super.text = newValue
                    updateWithSpacing()
                }
                get {
                    return super.text
                }
            }
            open override var attributedText: NSAttributedString? {
                set {
                    super.attributedText = newValue
                    updateWithSpacing()     
                }
                get {
                    return super.attributedText
                }
            }
            func updateWithSpacing() {
                let attributedString = self.attributedText == nil ? NSMutableAttributedString(string: self.text ?? "") : NSMutableAttributedString(attributedString: attributedText!)
                attributedString.addAttribute(NSKernAttributeName, value: self.characterSpacing, range: NSRange(location: 0, length: attributedString.length))
                super.attributedText = attributedString
            }
        }
        

        【讨论】:

          【解决方案13】:

          编程方法。(试试这个,它应该适合你)
          注意:我在 Swift 4

          中进行了测试
          let label = UILabel()
          let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
          let attrString = NSMutableAttributedString(string: stringValue)
          var style = NSMutableParagraphStyle()
          style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
          style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40
          
          // Line spacing attribute
          attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
          
          // Character spacing attribute
          attrString.addAttribute(NSAttributedStringKey.kern, value: 2, range: NSMakeRange(0, attrString.length))
          
          label.attributedText = attrString
          

          【讨论】:

            【解决方案14】:

            斯威夫特 5.3.1

            extension UILabel {
              func addCharacterSpacing(kernValue: Double = 1.15) {
                if let labelText = text, labelText.count > 0 {
                  let attributedString = NSMutableAttributedString(string: labelText)
                    attributedString.addAttribute(NSAttributedString.Key.kern, value: kernValue, range: NSRange(location: 0, length: attributedString.length - 1))
                  attributedText = attributedString
                }
              }
            }
            

            【讨论】:

            • 这与@budidino 的回答有何不同?
            • @craft 'NSAttributedStringKey' 已重命名为 'NSAttributedString.Key'
            猜你喜欢
            • 2012-06-19
            • 2016-10-07
            • 1970-01-01
            • 1970-01-01
            • 2011-03-26
            • 1970-01-01
            • 1970-01-01
            • 2020-12-01
            • 1970-01-01
            相关资源
            最近更新 更多