String boundingRect计算的高度与UITextView内容高度

时间:2017-05-06 19:47:01

标签: ios swift uitableview swift3 uitextview

我有一个UITableView,可变大小的单元格。高度基于我需要显示的文本块,因此我需要测量文本。

我只是使用了一些Lorem Ipsum文本:

  

“Nullam est elit,rutrum volutpat scelerisque eu,tincidunt ut magna。   Quisque坐在aodi odio quis eros lobortis cursus。菜豆属(Phasellus mauris)   augue,mattis a posuere sit amet,dictum sit amet ipsum。 Praesent   velit sapien,tristique ut pellentesque eget,venenatis in est。   Curabitur accumsan lacus nec ultricies finibus。在commodo,turpis在   auctor lobortis,augue ipsum tincidunt lorem,vitae fringilla libero   magna eget tortor。 Sed et ultrices odio,et viverra diam。 Mauris   semper non lorem varius sollicitudin。 Maecenas nec dui lectus。在hac   栖息地平原唯一。 Quisque sapien ex,pretium id vehicula   在nisl的eget,tempus。类别taciti sociosqu ad litora torquent   每个conubia nostra,每个inceptos himenaeos。 Aliquam vel sollicitudin   velit,efficitur accumsan sem。 Quisque id urna blandit,cursus justo   sed,aliquet velit。 Nullam id ipsum pellentesque,gravida nulla ut,   临时自由。“

当我调用ceil(text.height())时,它返回386.0高,但是当我将该文本放入UITextView并打印出UITextView的内容大小时,它表示内容为422.0高。 (即我的文字被切断了,因为UITextView不够高,无法显示所有内容。)

为什么会有区别?

我正在使用以下String扩展来计算文本的高度:

extension String {

    func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

        return boundingBox.height
    }

}

然后在tableView(heightForRowAt:)中我计算文本的高度并将其添加到textview上方和下方的空间以获得完整的单元格高度(在我开始调试之前这更加优雅):

let textviewWidth = self.view.frame.size.width-CGFloat(32)
let spaceAboveTextView = CGFloat(45)
let spaceBelowTextView = CGFloat(16)
let textHeight = ceil(text.height(withConstrainedWidth: textviewWidth, font: UIFont.systemFont(ofSize: 17.0)))
let height = spaceAboveTextView + textHeight + spaceBelowTextView

我已经验证UITextView使用的是大小为17的系统字体,它与我上面的代码匹配。

我已经验证了UITextView的框架(显示后)是(16.0, 45.0, 382.0, 385.6667),因此spaceAboveTextView=45是准确的,width=382是准确的。我还检查了UITextView上的约束,它的边缘约束为8pt,余量为8pt,spaceBelowTextView总共为16pt。

那么,我做错了什么?

2 个答案:

答案 0 :(得分:4)

您很可能遇到问题,因为您忘记考虑textContainerInset(可能还有文字视图的其他内容)。

默认情况下,它们从顶部,左侧和右侧分别为8。

尝试将代码更改为:

let textviewWidth = self.view.frame.size.width-CGFloat(32)-textView.textContainerInset.left-textView.textContainerInset.right
let spaceAboveTextView = CGFloat(45)+textView.textContainerInset.top
// bottom space is 0 by default. But lets add it just in case ;)
let spaceBelowTextView = CGFloat(16)+textView.textContainerInset.bottom
let textHeight = ceil(text.height(withConstrainedWidth: textviewWidth, font: UIFont.systemFont(ofSize: 17.0)))
let height = spaceAboveTextView + textHeight + spaceBelowTextView

我刚测试了这个解决方案,它适用于我的系统字体大小为17.如果这不起作用,请告诉我。

答案 1 :(得分:0)

测量用于在屏幕上显示的文本很困难,因为系统会更改字体和间距等,以使文本在CRT上更清晰(例如,它可以将屏幕字体替换为矢量字体)。即使这样,当使用具有高上升或下降的字符时,也可能会有一些重叠。

NSString和NSAttributedStrings具有测量例程,用于计算当前图形上下文中文本的边界大小。见boundingRectWithSize:options:attributes:context:。过去我在没有方便的CGContext时强制使用栅格指标的做法是创建一个小的屏幕外位图上下文(比如大小为1像素)并在测量文本时将其设置为当前上下文。

你想要寻找的另一件事是UITextView吸引它的textContainer而不是它的框架。 IIRC默认容器是框架插入4或5像素。