具有段落样式行间距的 UILabel

UILabel with Paragraph Style Line Spacing

我正在尝试创建消息传递应用程序,但遇到了一个非常奇怪的问题。

"Thomas" 和文本气泡底部之间有这么多 space 的原因是因为 UILabel 正在创建另一行。目前我正在使用 attributedText 属性 设置标签的文本,并传入 NSMutableParagraphStyle8line spacing。如果我将 line spacing 设置为 0,"Thomas" 和文本气泡底部之间的 space 会消失,如下所示:

这就是它变得奇怪的地方。如果我将段落 line spacing 设置回 8,并向该行添加更多字符,文本气泡将出现而没有额外的行:

非常感谢所有帮助:)

这是我的代码:

class MessageTableViewCell: UITableViewCell {
    var didSetupConstraints = false

    var thumbnail = UIImageView.newAutoLayoutView()
    let messageTailIcon = UIImageView.newAutoLayoutView()
    var messageView = UIView.newAutoLayoutView()
    var messageLabel = UILabel.newAutoLayoutView()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupViews()
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupViews() {
        thumbnail.image = UIImage(named: "ThomasBaldwin")
        thumbnail.layer.cornerRadius = 17.5
        thumbnail.clipsToBounds = true

        messageTailIcon.image = UIImage(named: "MessageTailIcon")

        messageView.backgroundColor = Application.greyColor
        messageView.layer.cornerRadius = 10

        let paragraphStyle = NSMutableParagraphStyle.new()
        paragraphStyle.lineSpacing = 8

        messageLabel.numberOfLines = 0
        messageLabel.layer.cornerRadius = 10
        messageLabel.attributedText = NSMutableAttributedString(
            string: "Thomas says hello",
            attributes: [
                NSFontAttributeName: UIFont(name: "AvenirNextLTPro-Regular", size: 12.5)!,
                NSForegroundColorAttributeName: UIColor.colorFromCode(0x262626),
                NSBackgroundColorAttributeName: Application.greyColor,
                NSKernAttributeName: 0.5,
                NSParagraphStyleAttributeName: paragraphStyle
            ]
        )

        contentView.addSubview(thumbnail)
        contentView.addSubview(messageView)
        messageView.addSubview(messageTailIcon)
        messageView.addSubview(messageLabel)
        updateConstraints()
    }

    override func updateConstraints() {
        if !didSetupConstraints {

            thumbnail.autoPinEdgeToSuperviewEdge(.Top, withInset: 15)
            thumbnail.autoPinEdgeToSuperviewEdge(.Leading, withInset: 8.5)
            thumbnail.autoSetDimensionsToSize(CGSize(width: 35, height: 35))

            messageView.autoPinEdgeToSuperviewEdge(.Top, withInset: 17.5)
            messageView.autoPinEdge(.Leading, toEdge: .Trailing, ofView: thumbnail, withOffset: 10)
            messageView.autoPinEdgeToSuperviewEdge(.Trailing, withInset: 24.5)
            messageView.autoPinEdgeToSuperviewEdge(.Bottom)

            messageTailIcon.autoPinEdgeToSuperviewEdge(.Top, withInset: 15)
            messageTailIcon.autoPinEdgeToSuperviewEdge(.Leading, withInset: -10)
            messageTailIcon.autoSetDimensionsToSize(CGSize(width: 18, height: 9))

            messageLabel.autoPinEdgesToSuperviewEdgesWithInsets(UIEdgeInsets(top: 8.5, left: 10, bottom: 8.5, right: 5), excludingEdge: .Trailing)
            messageLabel.autoPinEdgeToSuperviewEdge(.Trailing, withInset: 0, relation: .GreaterThanOrEqual)

            didSetupConstraints = true
        }

        super.updateConstraints()
    }

}

如果您想查看演示该问题的示例项目,我已将其中一个推送到 github

好的,所以终于锁定和简单的答案,这只与您的 KERNING 属性有关。看这个:

同样忽略红色单元格的大小,这在应用程序中不会发生这种情况,这只是我的屏幕截图大小不同的产物,但请您自己尝试一下。注释掉字距调整并重新应用它,您会看到相同的东西

带字距调整带 "Thomas"

无字距调整 "Thomas"

带字距调整带 "Thomas says hello"

无字距调整 "Thomas says hello"

我已经尽一切可能检查代码,使用不同的约束,我什至尝试了 NSAttributedString 的所有选项,唯一改变这种不良行为的是字距调整属性,它正在这样做适用于所有类型的字体,而不仅仅是 Avenir。事实上,当你根本没有设置字体时,你在这个例子中使用的字体是系统字体,但我现在已经用 3 种字体尝试过,同样的效果,字距似乎被打破了或者它可能按预期工作对于 Swift and/or ObjC,但我认为这实际上是一个错误。

大多数 NSAttributedString 选项,如果你想弄乱这些东西:

    var myString1 = NSMutableAttributedString(string:"Thomas asdfadsf asdfasdfasdf asdfasdf asdfasdf \n asdfasdf asdf \n")

    let myString1Font1 = UIFont.systemFontOfSize(12.0)

    let originalNSString = myString1.string as NSString
    let myString1Range1 = originalNSString.rangeOfString(myString1.string)

    var myString1ParaStyle1 = NSMutableParagraphStyle()
    myString1ParaStyle1.alignment = NSTextAlignment.Natural
    myString1ParaStyle1.baseWritingDirection = NSWritingDirection.Natural
    myString1ParaStyle1.defaultTabInterval = 0.0
    myString1ParaStyle1.firstLineHeadIndent = 0.0
    myString1ParaStyle1.headIndent = 0.0
    myString1ParaStyle1.hyphenationFactor = 0.0
    myString1ParaStyle1.lineBreakMode = NSLineBreakMode.ByWordWrapping
    myString1ParaStyle1.lineHeightMultiple = 0.0
    myString1ParaStyle1.lineSpacing = 8.0
    myString1ParaStyle1.maximumLineHeight = 0.0
    myString1ParaStyle1.minimumLineHeight = 0.0
    myString1ParaStyle1.paragraphSpacing = 0.0
    myString1ParaStyle1.paragraphSpacingBefore = 0.0
    myString1ParaStyle1.tailIndent = 0.0

    myString1.addAttribute(NSKernAttributeName, value:0.5, range:myString1Range1)
    myString1.addAttribute(NSFontAttributeName, value:myString1Font1, range:myString1Range1)
    myString1.addAttribute(NSParagraphStyleAttributeName, value:myString1ParaStyle1, range:myString1Range1)
    myString1.addAttribute(NSBackgroundColorAttributeName, value:UIColor.redColor(), range:myString1Range1)
    myString1.addAttribute(NSForegroundColorAttributeName, value:UIColor.blackColor(), range:myString1Range1)

再次强调,这不是约束问题,我错了,这只是 KERNING 问题,这很糟糕,但这就是生活,也许这需要向 RADAR 报告。

此外,您可以自己尝试一下,除了 0 或 0.00000 或您想要的任意多个零之外的任何内容都会产生错误的字距调整结果,我试过了,它会像字距调整一样弄乱您的标签字段会弄乱具有更大值的字段:

 NSKernAttributeName: 0.00000000000001

等等,我解决了它,从它的样子,设置这个值,只需将它添加到你在示例项目中设置的 paragraphStyle 变量,它与字距调整一起工作,不确定这是否有效对于所有字体,但它至少修复了您的示例项目:

paragraphStyle.lineHeightMultiple = 1.5

此方法的唯一问题是它适用于只有一个单词或一行的行,您必须根据新行出现的时间进行字数调整来设置此 "lineHeightMultiple",这很糟糕,但它很有效,显然,这不是一个很好的使用方法,但如果你有一个 1 衬里字符串就可以工作,如果你有更多则需要调整,否则只需关闭字距调整,它会在没有这个行高倍数的情况下解决.

好像行高在内部发生变化并将字符推到新行,但 Apple 不会自动考虑字符宽度的这种变化。

事实上,我认为您正在寻找的答案根本不是字距调整,而是字距调整,字距调整会使字母彼此分开。字距调整的问题是字距调整会影响字体的字形并覆盖它们的某些行为,因此它可能会像我们在这里看到的那样产生明显的效果。

来自苹果:

preferredFontForTextStyle:, the specific font returned includes traits which vary according to user preferences and context, including tracking (letter-spacing) adjustments, in addition to being tuned for the use specified by the particular text style constant. The fonts returned using text style constants are meant to be used for all text in an app other than text in user interface elements, such as buttons, bars, and labels. Naturally, you need to choose text styles that look right in your app. It’s also important to observe the UIContentSizeCategoryDidChangeNotification so that you can re–lay out the text when the user changes the content size category. When your app receives that notification, it should send the invalidateIntrinsicContentSize message to views positioned by Auto Layout or send setNeedsLayout to user interface elements positioned manually. And it should invalidate preferred fonts or font descriptors and acquire new ones as needed.

https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/TypoFeatures/TextSystemFeatures.html

如果您真的需要字距调整,那么如果字体有任何可用的字距调整值,那么您可能应该调整连字的字距调整值。

其他需要考虑的事情,这确实有效,但它也是粗体,所以它已经不符合你上面的风格,但它是你可以玩弄的东西:

let sytemDynamicFontDescriptor = UIFontDescriptor.preferredFontDescriptorWithTextStyle(UIFontTextStyleHeadline)
let size = sytemDynamicFontDescriptor.pointSize
let myString1Font1 = UIFont(descriptor: sytemDynamicFontDescriptor, size:size)

println(sytemDynamicFontDescriptor.fontAttributes())

messageLabel.numberOfLines = 0
messageLabel.layer.cornerRadius = 10

messageLabel.attributedText = NSMutableAttributedString(
    string: "Thomas asdfad as ",
    // string: "Thomas says hello", // switch back to this to see it display the text properly on one
    attributes: [
        NSFontAttributeName: myString1Font1,
        NSForegroundColorAttributeName: UIColor.blackColor(),
        NSBackgroundColorAttributeName: UIColor.redColor(),
        NSKernAttributeName: 0.5,
        NSParagraphStyleAttributeName: paragraphStyle
    ]
)