防止 UITextView 偏移其文本容器

Prevent UITextView from offsetting its text container

我想在用户输入文本时动态修改 UITextView 的高度(达到最大高度)。当文本视图中的行数为偶数时,我遇到了一个非常奇怪的行为。

我正在使用自动版式,文本视图有高度限制。我响应对文本视图委托 (textViewDidChange(_:)) 的调用,我在其中根据 contentSize.

计算和调整高度约束

代码如下:

func textViewDidChange(_ textView: UITextView) {
    let newHeight = textView.contentSize.height
    let newConstraintConst = max(MinTextViewHeight, min(MaxTextViewHeight, newHeight))
    self.textViewHeightConstraint.constant = newConstraintConst
}

效果很好,它将框架的大小调整到 MaxTextViewHeight,然后文本视图可以滚动。但是,当文本视图中的行数为偶数时,文本视图会在其NSTextContainer的底部添加一种偏移量,导致顶部的行被截断:

但是,当有奇数行时,NSTextContainer 不再偏移:

起初我以为它被文本视图的 textContainerInset 以某种方式控制,但它仅用于填充 space 内部 NSTextContainer,因为将其设置为 .zero 会删除内部的 space 但不会影响偏移量(顺便说一句,它会变得更糟,因为顶行几乎完全消失):

我查看了 UITextView class 参考资料,但没有看到任何 属性 可以让我操纵甚至获取此偏移量的值。

作为解决方法,我增加了文本容器的顶部插图并删除了底部插图:

textView.textContainerInset = UIEdgeInsetsMake(10, 0, 0, 0)

到目前为止这有效,但我通过反复试验得出了 10 的值,到目前为止我只在一台设备上测试过它。

我对需要脆弱的固定值的更复杂的变通方法不感兴趣;我试图了解如何设置此偏移量以及修复它的正确方法。希望有高人指点,谢谢!

只是一个猜测,但我认为问题在于文本视图假定调用 textViewDidChange 时自身的高度不会改变,所以它会在它认为必须滚动时滚动,无论你如何改变它的框架。

不确定您是否认为我的解决方案太老套了,但这会在您不需要时阻止它滚动。只要想要的内容大小小于您的最大大小,我只是将内容偏移量固定到顶部。

只需添加:

func scrollViewDidScroll(scrollView: UIScrollView) {
    if textView.contentSize.height <= MaxTextViewHeight && textView.contentOffset.y > 0.0 {
        textView.contentOffset.y = 0.0;
    }

}