是否有一个好的方法来调整UITextView的大小以符合其内容?例如,我有一个包含一行文本的UITextView:

"Hello world"

然后我添加了另一行文本:

"Goodbye world"

在Cocoa Touch中是否有一个好的方法来获取矩形来保存文本视图中的所有行,这样我就可以相应地调整父视图?

另一个例子是,查看Calendar应用程序中用于事件的notes字段——注意单元格(以及它包含的UITextView)如何展开以保存notes字符串中的所有文本行。


当前回答

结合迈克·麦克马斯特的回答,你可能会想这样做:

[myTextView setDelegate: self];

...

- (void)textViewDidChange:(UITextView *)textView {
  if (myTextView == textView) {
     // it changed.  Do resizing here.
  }
}

其他回答

在iOS6中,你可以在设置文本后检查UITextView的contentSize属性。在iOS7中,这将不再有效。如果你想在iOS7中恢复这个行为,把下面的代码放在UITextView的子类中。

- (void)setText:(NSString *)text
{
    [super setText:text];

    if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
        CGRect rect = [self.textContainer.layoutManager usedRectForTextContainer:self.textContainer];
        UIEdgeInsets inset = self.textContainerInset;
        self.contentSize = UIEdgeInsetsInsetRect(rect, inset).size;
    }
}

对于iOS 7.0,不是将frame.size.height设置为contentSize. height。使用[textView sizeToFit]。

看这个问题。

看起来这个家伙为NSTextView找到了答案,他的答案也适用于iOS。事实证明,intrinsicContentSize并不与布局管理器同步。如果一个布局发生在intrinsicContentSize之后,你可能会有一个差异。

他有一个简单的解决办法。

NSOutlineView中的NSTextView与IntrinsicContentSize设置错误的高度

这对于Swift 5来说很好,以防你想要适合你的TextView,一旦用户在运行中写文本。

只需实现UITextViewDelegate:

func textViewDidChange(_ textView: UITextView) {
    let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
    textView.frame.size = CGSize(width: newSize.width, height: newSize.height)
}

用键值观察(KVO)很简单,只需创建UITextView的子类,然后做:

private func setup() { // Called from init or somewhere

    fitToContentObservations = [
        textView.observe(\.contentSize) { _, _ in
            self.invalidateIntrinsicContentSize()
        },
        // For some reason the content offset sometimes is non zero even though the frame is the same size as the content size.
        textView.observe(\.contentOffset) { _, _ in
            if self.contentOffset != .zero { // Need to check this to stop infinite loop
                self.contentOffset = .zero
            }
        }
    ]
}
public override var intrinsicContentSize: CGSize {
    return contentSize
}

如果你不想子类化,你可以尝试做textView。bounds = textView。contentSize观察者中的contentSize。