在 Interface Builder 中更改 UILabel 上的字符间距

Posted

技术标签:

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

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

【问题讨论】:

我 99% 确定 Xcode 6 不支持这个。 @Drux 我 99% 确定 Xcode 6 可以做 IBDesignables 【参考方案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://***.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'

以上是关于在 Interface Builder 中更改 UILabel 上的字符间距的主要内容,如果未能解决你的问题,请参考以下文章

通过 Interface Builder 更改 UIView 属性

在 Interface Builder 中使用 Auto Layout 更改方向

如何在 Interface Builder 中更改 UIButton 的背景图像并保留其形状?

为啥在 Interface Builder 中更改字体大小会阻止 UILabel 调整大小以适应内容?

如何指定我希望 UI 元素在 Interface Builder 中进行方向更改的位置?

iOS:以编程方式更改从 Interface Builder 设置的约束