NSAttributedString boundingRect returns wrong height

末鹿安然 提交于 2019-12-11 06:19:54

问题


I calculate the height of an NSAttributedString like this.

let maxSize = NSSize(width: w, height: CGFloat.greatestFiniteMagnitude)
let rect = boundingRect(with: maxSize, options: [.usesFontLeading, .usesLineFragmentOrigin])
let height = rect.integral.size.height

I tried about every "hack" that was mentioned on SO, yet the string height gets more inaccurate the smaller the width gets (the calculated height is larger than the actual height).

According to other posts the following things cause problems with size calculation:

  • Whitespace
  • No foreground color
  • No background color
  • Widths below 300 don't work (?)

I have found that none of these suggestions make any difference. The attributed string is a concatenation of lines, each having a foregroundColor and backgroundColor. The string also has the following paragraph style.

 let pstyle = NSMutableParagraphStyle()
 pstyle.lineSpacing = 6
 pstyle.lineBreakMode = .byWordWrapping

and a userFixedPitchFont of size 11.

Why does the height error get larger the smaller the width is?

PS: I imagine it has something to do with lineBreak since the error gets larger if more lines are word wrapped.


回答1:


I found that this solution works. Note that if you don't set the lineFragmentPadding to 0, it produces the same (wrong) results as boundingRect.

extension NSAttributedString {

    func sizeFittingWidth(_ w: CGFloat) -> CGSize {
        let textStorage = NSTextStorage(attributedString: self)
        let size = CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)
        let boundingRect = CGRect(origin: .zero, size: size)

        let textContainer = NSTextContainer(size: size)
        textContainer.lineFragmentPadding = 0

        let layoutManager = NSLayoutManager()
        layoutManager.addTextContainer(textContainer)

        textStorage.addLayoutManager(layoutManager)

        layoutManager.glyphRange(forBoundingRect: boundingRect, in: textContainer)

        let rect = layoutManager.usedRect(for: textContainer)

        return rect.integral.size
    }
}


来源:https://stackoverflow.com/questions/54497598/nsattributedstring-boundingrect-returns-wrong-height

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!