如何将UITextView的大小调整为其内容?

dre*_*ewh 512 cocoa-touch uitextview uikit ios autolayout

有没有一种很好的方法来调整a的大小UITextView以符合其内容?比方说我有一个UITextView包含一行文字:

"Hello world"
Run Code Online (Sandbox Code Playgroud)

然后我添加另一行文字:

"Goodbye world"
Run Code Online (Sandbox Code Playgroud)

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

再举一个例子,查看日历应用程序中事件的注释字段 - 注意单元格(及其UITextView包含)如何扩展以包含注释字符串中的所有文本行.

jhi*_*erd 601

这适用于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;
}
Run Code Online (Sandbox Code Playgroud)

或者在Swift中(与iOS 11中的Swift 4.1一起使用)

let fixedWidth = textView.frame.size.width
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
textView.frame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
Run Code Online (Sandbox Code Playgroud)

如果您想要支持iOS 6.1,那么您还应该:

textview.scrollEnabled = NO;
Run Code Online (Sandbox Code Playgroud)

  • 我需要`textview.scrollEnabled = NO;`以防止文本在iOS 7中被切断. (33认同)
  • 我建议使用`CGFLOAT_MAX`宏而不是'MAXFLOAT`.适用于32/64位平台. (19认同)
  • +1对于scrollEnabled = NO,这节省了我的一天 (9认同)
  • 为什么在Swift版本中有两个单独的sizeThatFits(...)调用?第一行是什么? (4认同)
  • 您也可以使用 INFINITY 代替 CGFLOAT_MAX 和 MAXFLOAT。看起来更搞笑 (2认同)
  • 在进入下一行之前面临很小波动的人添加了这个`NSRange bottom = NSMakeRange(textView.text.length -1,1); [textView scrollRangeToVisible:bottom];` (2认同)

Ron*_*iew 576

这不再适用于iOS 7或更高版本

实际上有一种非常简单的方法可以调整UITextView内容的正确高度.它可以使用UITextView contentSize.

CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;
Run Code Online (Sandbox Code Playgroud)

有一点要注意的是,正确的contentSize是唯一可用UITextView已加入的观点addSubview.在此之前它等于frame.size

如果自动布局为ON,则无效.使用自动布局时,一般方法是使用该sizeThatFits方法并更新constant高度约束上的值.

CGSize sizeThatShouldFitTheContent = [_textView sizeThatFits:_textView.frame.size];
heightConstraint.constant = sizeThatShouldFitTheContent.height;
Run Code Online (Sandbox Code Playgroud)

heightConstraint 是您通常通过将属性链接到故事板中创建的高度约束来通过IBOutlet设置的布局约束.


只是为了增加这个惊人的答案,2014年,如果你:

[self.textView sizeToFit];
Run Code Online (Sandbox Code Playgroud)

仅与iPhone6 +的行为有所不同:

在此输入图像描述

只有6+(不是5s或6),它确实为UITextView添加了"一个空行"."RL解决方案"完美地解决了这个问题:

CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;
Run Code Online (Sandbox Code Playgroud)

它解决了6+以上的"额外线路"问题.

  • 使用[_textView sizeToFit]刷新contentSize属性,删除了预先将其添加到scrollView的要求. (11认同)
  • 啊哈!我正在设置文本视图高度,然后调整包含视图的高度.显然,当我这样做时,文本视图高度正在调整.首先设置包含视图高度可以使事情按预期工作(或者更好,希望如此). (4认同)
  • 这是关于调整外部容器的大小.在iOS 7中,这种行为发生了变化.我在链接的问题中显示了添加sizeToFit和layoutIfNeeded的位置. (4认同)
  • 你救了我的一天.我正在努力与selfCalculating类函数扩展忘记这一点.谢谢. (2认同)

Bre*_*ald 90

为了UITextView在内部进行动态调整UITableViewCell,我发现以下组合在Xcode 6中与iOS 8 SDK一起使用:

  • 添加UITextView到a UITableViewCell并将其约束到两侧
  • 设置UITextViewscrollEnabled属性NO.启用滚动后,其框架UITextView与其内容大小无关,但在禁用滚动的情况下,两者之间存在关系.
  • 如果您的表使用原始默认行高44,那么它将自动计算行高,但如果您将默认行高更改为其他行,则可能需要手动启用行高的自动计算viewDidLoad:

    tableView.estimatedRowHeight = 150;
    tableView.rowHeight = UITableViewAutomaticDimension;
    
    Run Code Online (Sandbox Code Playgroud)

对于只读的动态调整大小UITextView,就是这样.如果您允许用户编辑您的文本UITextView,您还需要:

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

    - (void)textViewDidChange:(UITextView *)textView;
    {
        [tableView beginUpdates];
        [tableView endUpdates];
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 并且不要忘记UITextView将代理设置在某个地方,无论是在内部Storyboard还是内部tableView:cellForRowAtIndexPath:

  • 对我来说不太合适.每次输入一个字符时,textViewDidChange方法都会导致我的tableview反弹.我建议不要在tableView:cellForRowAtIndexPath方法中使用该方法,对于带有textview的行,如果你处于只读模式,则将.scrollEnabled设置为NO,如果你在编辑视图集中滚动启用为YES.这种方式只显示它将始终显示全文,编辑时将以全文开头,当您添加更多文本时将保持相同的大小,前面的文字滚动到顶部 (4认同)
  • 此外,我在textview中添加了一个> = height约束,因为空文本字段没有高度,无法点击开始编辑. (3认同)

Alo*_*lok 63

使用代码和故事板的非常简单的工作解决方案.

按代码

textView.scrollEnabled = false
Run Code Online (Sandbox Code Playgroud)

通过故事板

取消选中滚动启用

在此输入图像描述

除此之外无需做任何事情.

  • 这个答案是对的.在StoryBoard中,您可以像UILabel一样使用TextView AutoSize.我们需要做的就是设置scrollEnabled = false. (5认同)
  • 基本上,这是正确的:如果您使用Autolayout约束并关闭滚动,整个过程都有效. (4认同)
  • @iOS 如果您要添加高度约束,则降低约束优先级,否则将无法工作。 (3认同)
  • 非常感谢。就是这么简单,只需禁用在故事板或代码中滚动即可,就像UILabel的第0行一样。 (2认同)

Jua*_*ero 58

斯威夫特:

textView.sizeToFit()
Run Code Online (Sandbox Code Playgroud)

  • 另外,我发现我需要将启用滚动设置为false才能使其正常工作.`textView.scrollEnabled = false` (14认同)
  • @tmarkiewicz当文本适合您设备的屏幕时,它会起作用,但当您的文本大于屏幕上的空间时,这将是一个问题.您将无法滚动它以查看文本的其余部分. (5认同)
  • 你应该记得在textView.sizeToFit()之后调用textView.layoutIfNeeded() (2认同)

小智 24

在我(有限)的经历中,

- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
Run Code Online (Sandbox Code Playgroud)

不尊重换行符,因此最终可能CGSize比实际需要的要短很多.

- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
Run Code Online (Sandbox Code Playgroud)

似乎确实尊重新线.

此外,文本实际上并未呈现在顶部UITextView.在我的代码中,我将新的高度设置为UITextViewsizeOfFont方法返回的高度大24个像素.

  • 它的大小就好像它会在UILabel上绘制文本一样.如果您将该大小设置为uitextview的框架,那么您仍然需要一些滚动. (3认同)

pha*_*ann 22

在iOS6中,您可以contentSize在设置文本后立即检查UITextView 的属性.在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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我在哪里可以阅读更多相关信息?对于iOS 7中看似新的行为,我完全迷失了. (2认同)

Nik*_*ook 18

我将在页面底部发布正确的解决方案,以防有人勇敢(或绝望)阅读到这一点.

这里有gitHub repo,他们不想阅读所有文本:resizableTextView

这适用于iOs7(我相信它适用于iOs8)和自动布局.你不需要魔术数字,禁用布局和类似的东西.简洁优雅的解决方案.

我认为,所有与约束相关的代码都应该转向updateConstraints方法.所以,让我们自己做ResizableTextView.

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

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

所以现在我们知道真实的contentSize,无论我们在哪里:之前或之后viewDidLoad.现在在textView上添加高度约束(通过故事板或代码,无论如何).我们将使用以下方式调整该值contentSize.height:

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

最后要做的就是告诉超类updateConstraints.

[super updateConstraints];
Run Code Online (Sandbox Code Playgroud)

现在我们的班级看起来像:

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];
}
Run Code Online (Sandbox Code Playgroud)

漂亮干净吧?而且您不必在控制器中处理该代码!

可是等等! 你没动画!

您可以轻松地动画更改以使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];
Run Code Online (Sandbox Code Playgroud)

  • 使用`CGFLOAT_MAX`,而不是'FLT_MAX`. (4认同)

Mik*_*ter 12

你试过[textView sizeThatFits:textView.bounds]吗?

编辑:sizeThatFits返回大小但实际上并未调整组件大小.我不确定这是不是你想要的,或者是否[textView sizeToFit]更符合你的要求.在任何一种情况下,我都不知道它是否完全适合您想要的内容,但这是首先尝试的.

  • sizetofit节省了一天 (2认同)

小智 9

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

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

这将返回适合给定字符串的矩形的大小.传递具有所需宽度和最大高度的大小,然后您可以查看返回的高度以适合文本.有一个版本可以让你指定换行模式.

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


Bre*_*don 8

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

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

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

这里,每个8占据了四个填充边缘之一,而100000只是一个非常大的最大尺寸.

在实践中,您可能想要font.leading在高度上添加额外的东西; 这会在文本下方添加一个空白行,如果文本视图正下方有视觉上很重的控件,则可能看起来更好.


Bar*_*zyk 7

以下内容就足够了:

  1. 只需记住将您的滚动设置为NOUITextView:

在此输入图像描述

  1. 正确设置自动布局约束.

你甚至可以使用UITableViewAutomaticDimension.


Kis*_*mar 7

我们可以通过约束来实现.

  1. 设置UITextView的高度约束. 在此输入图像描述

2.为该高度约束创建IBOutlet.

 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtheightconstraints;
Run Code Online (Sandbox Code Playgroud)

3.不要忘记为你的textview设置委托.

4.

-(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);
    NSLog(@"this is updating height%@",NSStringFromCGSize(newFrame.size));
    [UIView animateWithDuration:0.2 animations:^{
                  _txtheightconstraints.constant=newFrame.size.height;
    }];

}
Run Code Online (Sandbox Code Playgroud)

然后像这样更新你的约束:)


Oli*_*lie 6

结合Mike McMaster的回答,您可能希望做以下事情:

[myTextView setDelegate: self];

...

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


小智 6

我发现了一种根据文本字段内部文本调整文本字段高度的方法,并根据文本字段的高度在其下方排列标签!这是代码.

UITextView *_textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 10, 300, 10)];
NSString *str = @"This is a test text view to check the auto increment of height of a text view. This is only a test. The real data is something different.";
_textView.text = str;

[self.view addSubview:_textView];
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;

UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 5 + frame.origin.y + frame.size.height, 300, 20)];
lbl.text = @"Hello!";
[self.view addSubview:lbl];
Run Code Online (Sandbox Code Playgroud)


Swa*_*p S 6

使用自动布局和你的sizetofit的人不起作用,请检查你的宽度约束一次.如果您错过了宽度约束,那么高度将是准确的.

无需使用任何其他API.只需一行即可解决所有问题.

[_textView sizeToFit];
Run Code Online (Sandbox Code Playgroud)

在这里,我只关心高度,保持宽度固定,并错过了我的TextView在故事板中的宽度约束.

这是为了显示来自服务的动态内容.

希望这可能有所帮助..


Chu*_*ger 6

从iOS 8开始,可以使用UITableView的自动布局功能自动调整UITextView的大小,而根本不需要自定义代码.我已经在github上放了一个项目来演示这个,但是关键是:

  1. UITextView必须禁用滚动,您可以通过编程方式或通过界面构建​​器执行此操作.如果启用滚动,则不会调整大小,因为滚动可让您查看更大的内容.
  2. 在UITableViewController的viewDidLoad中,必须为estimatedRowHeight设置一个值,然后将其设置rowHeightUITableViewAutomaticDimension.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.estimatedRowHeight = self.tableView.rowHeight;
    self.tableView.rowHeight = UITableViewAutomaticDimension;
}
Run Code Online (Sandbox Code Playgroud)
  1. 项目部署目标必须是iOS 8或更高版本.


Pet*_*ger 5

我查看了所有答案,所有答案均保持固定宽度,仅调整高度。如果您还希望调整宽度,则可以很容易地使用此方法:

因此在配置文本视图时,请禁用滚动

textView.isScrollEnabled = false
Run Code Online (Sandbox Code Playgroud)

然后在委托方法中func textViewDidChange(_ textView: UITextView)添加以下代码:

func textViewDidChange(_ textView: UITextView) {
    let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
    textView.frame = CGRect(origin: textView.frame.origin, size: newSize)
}
Run Code Online (Sandbox Code Playgroud)

输出:

在此处输入图片说明

在此处输入图片说明


ali*_*ara 5

禁用滚动

添加约束

并添加您的文字

[yourTextView setText:@"your text"];
[yourTextView layoutIfNeeded];
Run Code Online (Sandbox Code Playgroud)

如果你使用,UIScrollView你也应该添加这个;

[yourScrollView layoutIfNeeded];

-(void)viewDidAppear:(BOOL)animated{
    CGRect contentRect = CGRectZero;

    for (UIView *view in self.yourScrollView.subviews) {
         contentRect = CGRectUnion(contentRect, view.frame);
    }
    self.yourScrollView.contentSize = contentRect.size;
}
Run Code Online (Sandbox Code Playgroud)


小智 5

使用 UITextViewDelegate 是最简单的方法:

func textViewDidChange(_ textView: UITextView) {
    textView.sizeToFit()
    textviewHeight.constant = textView.contentSize.height
}
Run Code Online (Sandbox Code Playgroud)