简体   繁体   中英

Prevent UITextView from offsetting its text container

I am tying to modify the height of a UITextView dynamically (up to a max height) while the user enters text. I am experiencing a very strange behavior when there are an even number of lines in the text view.

I am using autolayout and the text view has a height constraint. I respond to calls to the text view's delegate ( textViewDidChange(_:) ), where I calculate and adjust the height constraint based on the contentSize .

Here is the code:

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

This works well, it resizes the frame up to MaxTextViewHeight and then the text view can scroll. However, when there are an even number of lines in the text view, the text view adds a kind of offset to the bottom of its NSTextContainer , causing the top line to be cut off:

顶线被切断

文本容器偏移

However, when there are odd lines the NSTextContainer is no longer offset:

顶线是正常的

文本容器是正常的

At first I thought it was somehow being controlled by the text view's textContainerInset but that is only used to pad the space inside the NSTextContainer , as setting it to .zero removes the space inside but does not affect the offset (and incidentally makes it even worse, as the top line almost completely disappears):

删除插图会使情况更糟

I have looked through the UITextView class reference and I don't see any property that would let me manipulate or even get the value of this offset.

As a workaround I am increasing the text container's top inset and removing the bottom inset:

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

在此处输入图片说明

This works so far, but I arrived at a value of 10 by trial-and-error, and so far I've only tested it on a single device.

I am not interested in more hacky workarounds that require fragile, fixed values; I am trying to understand how this offset is being set and a proper way to fix it. I'm hoping that someone can provide some insight, thanks!

Just a speculation, but I think the problem is that the text view assumes that the height of itself does not change while calling textViewDidChange , so it scrolls when it thinks it has to, regardless of you changing its frame.

Not sure if you think my solution is too hacky, but this will stop it from scrolling when you don't want it. I simply pin the content offset to the top as long as the wanted content size is smaller than your max size.

Just add this:

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

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM