【问题标题】:Align baselines with characters in large line heights with Text Kit使用 Text Kit 将基线与大行高的字符对齐
【发布时间】:2016-11-17 14:03:32
【问题描述】:

当我使用 Text Kit 绘制具有固定行高的属性字符串时,字符总是与行片段的底部对齐。虽然这在字符大小不同的一行上是有意义的,但这会破坏多行文本的流动。基线的出现由每行的最大下降点决定。

我从 Sketch 背后的人那里找到了 article,更详细地解释了这个确切的问题并展示了他们的解决方案的作用,但显然没有解释 如何他们实现了这一目标。 p>

这基本上是我想要的:

当显示两条线高较大的线时,这个结果远非理想:

我正在使用的代码:

let smallFont = UIFont.systemFont(ofSize: 15)
let bigFont = UIFont.systemFont(ofSize: 25)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.minimumLineHeight = 22
paragraphStyle.maximumLineHeight = 22
var attributes = [
    NSFontAttributeName: smallFont,
    NSParagraphStyleAttributeName: paragraphStyle
]

let textStorage = NSTextStorage()
let textContainer = NSTextContainer(size: CGSize(width: 250, height: 500))
let layoutManager = NSLayoutManager()
textStorage.append(NSAttributedString(string: "It is a long established fact that a reader will be ", attributes:attributes))
attributes[NSFontAttributeName] = bigFont
textStorage.append(NSAttributedString(string: "distracted", attributes:attributes))
attributes[NSFontAttributeName] = smallFont
textStorage.append(NSAttributedString(string: " by the readable content of a page when looking at its layout.", attributes:attributes))

layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)

let textView = UITextView(frame: self.view.bounds, textContainer:textContainer)
view.addSubview(textView)

【问题讨论】:

    标签: ios swift macos textkit


    【解决方案1】:

    我设法让它工作,但不幸的是不得不放弃对 iOS 8 和 macOS 10.10 的支持。

    如果您实现NSLayoutManager 的以下委托调用,您可以决定如何处理每个行片段的baselineOffset

    optional func layoutManager(_ layoutManager: NSLayoutManager, 
     shouldSetLineFragmentRect lineFragmentRect: UnsafeMutablePointer<CGRect>, 
                           lineFragmentUsedRect: UnsafeMutablePointer<CGRect>, 
                                 baselineOffset: UnsafeMutablePointer<CGFloat>, 
                               in textContainer: NSTextContainer, 
                       forGlyphRange glyphRange: NSRange) -> Bool
    

    NSTextStorage 被创建并且每次后续更改时,我都会枚举所有使用的字体,计算它的默认行高(NSLayoutManager.defaultLineHeightForFont())并存储最大的行高。在上述委托方法的实现中,我检查NSParagraphStyle 的当前行高以获取所提供的行片段,并在该值内对齐字体的行高。从那里可以计算基线偏移量,知道基线位于字体的ascenderdescender 之间。用baselineOffset.memory(newOffset) 更新baselineOffset 值,一切都应该按照您的意愿对齐。

    注意:我不会详细介绍用于实现此功能的实际代码,因为我不确定我在这些计算中是否使用了正确的值。当整个方法经过尝试和验证时,我可能会在不久的将来更新此内容。

    更新:调整基线的实施。每次 textContainer 更改时,我都会重新计算最大的行高和最大的下降器。然后我基本上是在布局管理器的委托函数中这样做的:

    var baseline: CGFloat = (lineFragmentRect.pointee.height - biggestLineHeight) / 2
    baseline += biggestLineHeight
    baseline -= biggestDescender
    baseline = min(max(baseline, 0), lineFragmentRect.pointee.height)
    baselineOffset.pointee = floor(baseline)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-02
      • 1970-01-01
      • 2011-03-07
      • 1970-01-01
      • 2020-10-03
      • 2020-10-04
      • 2014-09-22
      • 2018-07-21
      相关资源
      最近更新 更多