Ios 字符串boundingRect计算高度不小于';不匹配UITextView内容高度

Ios 字符串boundingRect计算高度不小于';不匹配UITextView内容高度,ios,swift,uitableview,swift3,uitextview,Ios,Swift,Uitableview,Swift3,Uitextview,我有一个具有可变大小单元格的UITableView。高度基于我需要显示的文本块,因此我需要测量文本 我只是在使用一些Lorem Ipsum文本: “最优秀的人,最优秀的人,最优秀的人,最优秀的人。 你坐在那里,我爱你,我爱你,我爱你,我爱你 奥古斯,马蒂斯是一位诗人,他是一位诗人,他是一位诗人 维利特·萨皮恩,特里斯蒂克·乌特·佩伦茨基·埃吉特,东部的威尼斯人。 在康莫多,turpis,在 拍卖人lobortis、奥古斯·伊普苏姆·廷西德·洛雷姆、维塔·弗林吉利亚·利伯 最大的侵权行为,最大的侵

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

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

“最优秀的人,最优秀的人,最优秀的人,最优秀的人。 你坐在那里,我爱你,我爱你,我爱你,我爱你 奥古斯,马蒂斯是一位诗人,他是一位诗人,他是一位诗人 维利特·萨皮恩,特里斯蒂克·乌特·佩伦茨基·埃吉特,东部的威尼斯人。 在康莫多,turpis,在 拍卖人lobortis、奥古斯·伊普苏姆·廷西德·洛雷姆、维塔·弗林吉利亚·利伯 最大的侵权行为,最大的侵权行为,最大的侵权行为 不含酒精的葡萄品种。不含酒精的葡萄品种 居住平台的名言。智者前,前车船 伊格特,nisl的坦普斯。一个有能力的社会团体 每一只小锥虫,每一只大锥虫,每一只小锥虫 维利特,积累的效率,我是布朗迪特,我是胡斯托 sed,aliquet velit,Nullam id ipsum pellentesque,孕妇nulla ut, 临时自由人。”

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

为什么会有区别

我使用以下字符串扩展名来计算文本的高度:

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
    }

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

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

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


那么,我做错了什么?

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

NSString和NSAttributedString具有计算当前图形上下文中文本边界大小的测量例程。看见在过去,当我没有方便的CGContext时,我所做的强制光栅度量是创建一个小的屏幕外位图上下文(比如1像素大小),并在测量文本时将其设置为当前上下文


另一个您想要寻找的是,UITextView将绘制到它的
textContainer
中,而不是绘制到它的框架中。IIRC默认容器是由4或5像素插入的帧。

最有可能出现问题,因为您忘记了将
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。如果这不起作用,请告诉我

澄清一下:您是否使用UITextView支持多行文本。如果是这样,重构将使用UILabel。只需将行数设置为0并设置约束即可。在没有其他需要的情况下,将UITextView设置为不滚动应该使其与任何其他视图一样具有自身大小。我面临同样的问题。你找到解决方案了吗?使用这段代码确实帮助我计算出正确的高度:我以前看过ContentInset,但它们都是零,我看过textContainer,但没有看到TextContainerSet。这些占了16多个点,所以这肯定有帮助,但我还是遗漏了一些东西。这个解决方案对短字符串有帮助,但对长字符串来说,高度差异是巨大的(在~1700个单词的属性字符串上超过250点)
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