ios - 如何调整UITextView到其内容?

  显示原文与译文双语对照的内容

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

"欢迎世界""

然后添加另一行文本:

"再见世界""

在 Cocoa Touch 中是否有一个好的方法来获取包含文本视图中所有行的rect,以便我可以相应地调整父视图?

作为另一个示例,查看日历application--note中事件的备注字段。单元格( 它包含的UITextView ) 如何展开以保存注释字符串中的所有文本行。

时间:

这适用于 iOS 6.1和 iOS 7:


- (void)textViewDidChange:(UITextView *)textView
{
 CGFloat fixedWidth = textView.frame.size.width;
 CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
 CGRect newFrame = textView.frame;
 newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
 textView.frame = newFrame;
}

如果你想要支持 iOS 6.1,那么你也应该:


textview.scrollEnabled = NO;

确实有一种非常简单的方法来调整 UITextView的大小,使它的达到正确的内容高度。 可以使用 UITextViewcontentSize 完成。


CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;

有一点要注意的是,正确的contentSize 只有 UITextView 后与 addSubview 已经添加到视图。 在这之前,它等于 frame.size

如果自动布局打开,这将不起作用。 使用自动布局,一般方法是使用 sizeThatFits 方法,并在高度约束上更新 constant 值。


CGSize sizeThatShouldFitTheContent = [_textView sizeThatFits:_textView.frame.size];
heightConstraint.constant = sizeThatShouldFitTheContent.height;

heightConstraint 布局约束,你通常通过连接属性设置通过 IBOutlet Storyboard 中创建的高度限制。


为了添加到这个惊人的答案,2014,如果你:


[self.textView sizeToFit];

iPhone6+的行为有差异:

enter image description here

对于 6 + 只有( 不是 5或者 6 ),它确实将"另一个空行"添加到 UITextView 。 "rl解决方案"完美地修复了这个问题:


CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;

它修复"额外线条"问题 6 +。

在我的( 有限) 经验中


- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode

不尊重换行符,因此你最终可以使用比实际需要的更短的CGSize


- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size

似乎是对换行符的尊重。

此外,文本实际上并不是在 UITextView的顶部呈现的。 在我的代码中,我设置了新的高度的UITextView 24像素大于高度 sizeOfFont 返回的方法。

在ios6,你可以检查 contentSize UITextView设置文本后的属性。 在ios中,这将不再工作。 如果要为 web parttra恢复这里行为,请将以下代码放在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;
 }
}

动态分级 UITextView UITableViewCell内,我发现下面的组合与ios 8sdk在xcode 6工作:

  • 在 Storyboard/ib中,将UITextView添加到UITableViewCell并将它的约束到边
  • 在 Storyboard/ib中,取消选中滚动( 启用滚动,UITextView的框架独立于内容大小,但使用滚动禁用,两者之间有一个关系)
  • 在viewDidLoad中,告诉tableView自动计算行高:

    
    tableView.estimatedRowHeight = 150;
    tableView.rowHeight = UITableViewAutomaticDimension;
    
    

对于read-only动态调整大小,这就是它。 如果允许用户编辑UITextView中的文本,你还需要:

  • 实现 textViewDidChange: UITextViewDelegate协议的方法,并告诉tableView每次编辑文本时都重新绘制自己:

    
    - (void)textViewDidChange:(UITextView *)textView;
    {
     [tableView beginUpdates];
     [tableView endUpdates];
    }
    
    
  • 不要忘记将UITextView委托设置在 Storyboard/ib或者 tableView:cellForRowAtIndexPath 中:

你尝试过 [textView sizeThatFits:textView.bounds]

编辑:sizeThatFits返回大小但不实际调整组件大小。 我不确定这是否是你想要的,或者如果 [textView sizeToFit] 是你想要的。 无论哪种情况,我都不知道它是否能完美地满足你想要的内容,但它是第一个。

另一种方法是查找使用 NSString 方法将占用的特定字符串的大小:

-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size

这将返回与给定的字体匹配给定字符串的矩形的大小。 通过所需宽度和最大高度传递一个大小,然后你可以查看返回的高度以适应文本。 有一个允许你指定换行符模式的版本。

然后,你可以使用返回的大小来更改视图的大小以适应。

我将在页面底部发布正确的解决方案,以防有人勇敢的( 或者despaired足够) 阅读至此。

下面是gitHub的仓库,他们不想阅读所有的文本: resizableTextView

这是 iOs7 ( 我相信它可以和iOs8一起工作) 和自动布局。 你不需要魔术数字,禁用布局和类似的东西。 简洁典雅的解决方案。

我认为所有constraint-related代码都应该转到 updateConstraints 方法。 那么,让我们自己制作 ResizableTextView

我们在这里遇到的第一个问题是,在 viewDidLoad 方法之前不知道真正的内容大小。 我们可以使用长而长的道路,根据字体大小,换行符,等等 计算它,但是我们需要强大的解决方案,所以我们需要:

CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];

所以现在我们知道了真正的contentSize无论我们在哪里: 在 viewDidLoad 之前或者之后。现在在 textView ( 通过 Storyboard 或者代码,无论如何) 上添加高度约束。 我们将使用 contentSize.height 调整该值:


[self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
 if (constraint.firstAttribute == NSLayoutAttributeHeight) {
 constraint.constant = contentSize.height;
 *stop = YES;
 }
}];

最后要做的是告诉超类 updateConstraints


[super updateConstraints];

现在我们的类看起来像:

ResizableTextView.m


- (void) updateConstraints {
 CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];

 [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
 if (constraint.firstAttribute == NSLayoutAttributeHeight) {
 constraint.constant = contentSize.height;
 *stop = YES;
 }
 }];

 [super updateConstraints];
}

漂亮干净,对你不必在你的控制器中处理代码? !

磅,但等待 磅无动画 !

你可以轻松设置更改动画,使 textView 平滑拉伸。 以下是一个示例:


 [self.view layoutIfNeeded];
//do your own text change here.
 self.infoTextView.text = [NSString stringWithFormat:@"%@, %@", self.infoTextView.text, self.infoTextView.text];
 [self.infoTextView setNeedsUpdateConstraints];
 [self.infoTextView updateConstraintsIfNeeded];
 [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{
 [self.view layoutIfNeeded];
 } completion:nil];

如果你没有( 例如你正在调整表格视图单元格的大小) UITextView 方便,你需要计算大小通过测量字符串,然后会计 8pt的填充 UITextView的两侧。 例如如果你知道文本视图所需的宽度,并想计算出相应的高度:


NSString * string =.. .;
CGFloat textViewWidth =.. .;
UIFont * font =.. .;

CGSize size = CGSizeMake(textViewWidth - 8 - 8, 100000);
size.height = [string sizeWithFont:font constrainedToSize:size].height + 8 + 8;

这里,每个 8占四垫边缘, 100000只是作为一个非常大的最大大小。

在实践中,你可能希望添加一个额外的font.leading 高度;这下添加一个空白行你的文本,这可能更好看如果有视觉文本视图下沉重的直接控制。

结合mcmaster的Mike回答,你可能想做以下事情:


[myTextView setDelegate: self];

...

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

...