首页 文章

如何根据内容调整UITextView的大小?

提问于
浏览
483

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

"Hello world"

然后我添加另一行文字:

"Goodbye world"

在Cocoa Touch中有一个很好的方法来获取 rect ,它将保存文本视图中的所有行,以便我可以相应地调整父视图吗?

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

30 回答

  • 9

    在我(有限)的经历中,

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

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

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

    确实似乎尊重新线 .

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

  • 3

    这适用于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;
    }
    

    或者在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)
    

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

    textview.scrollEnabled = NO;
    
  • 1

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

    实际上有一种非常简单的方法可以将 UITextView 的大小调整为其正确的内容高度 . 可以使用 UITextView contentSize 完成 .

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

    需要注意的一点是,正确的 contentSize 仅可用 after UITextView 已添加到视图中 addSubview . 在此之前它等于 frame.size

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

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

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


    只是为了增加这个惊人的答案,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上的“额外线”问题 .

  • 571

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

    • UITextView 添加到 UITableViewCell 并将其约束到两侧

    • UITextViewscrollEnabled 属性设置为 NO . 启用滚动后, UITextView 的框架与其内容大小无关,但在禁用滚动的情况下,两者之间存在关系 .

    • 如果您的表使用原始默认行高44,那么它将自动计算行高,但如果您将默认行高更改为其他行,则可能需要在 viewDidLoad 中手动启用行高的自动计算:

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

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

    • 实现 UITextViewDelegate 协议的 textViewDidChange: 方法,并在每次编辑文本时告诉 tableView 重绘自身:
    - (void)textViewDidChange:(UITextView *)textView;
    {
        [tableView beginUpdates];
        [tableView endUpdates];
    }
    
    • 并且不要忘记在 StoryboardtableView:cellForRowAtIndexPath: 中的某处设置 UITextView 委托
  • 1

    Swift :

    textView.sizeToFit()
    
  • 24

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

    按代码

    textView.scrollEnabled = false
    

    通过故事板

    取消选中 Scrolling Enable

    enter image description here

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

  • 8

    在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;
        }
    }
    
  • 4

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

    对于那些不想阅读所有文本的人来说,这是gitHub回购:resizableTextView

    This works with iOs7 (and I do believe it will work with iOs8) and with autolayout. You don't need magic numbers, disable layout and stuff like that. 简短而优雅的解决方案 .

    我认为,所有与约束相关的代码都应该转到 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;
        }
    }];
    

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

    [super updateConstraints];
    

    现在我们的 class 看起来像:

    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];
    }
    

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

    But wait! Y NO ANIMATION!

    您可以轻松地为更改设置动画,以使 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];
    
  • 53

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

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

  • 559

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

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

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

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

  • 6

    如果你没有 UITextView 方便(例如,你必须通过测量字符串来计算尺寸,那么在 UITextView 的每一边都要考虑8磅的填充 . 例如,如果你知道所需的宽度您的文本视图,并想要找出相应的高度:

    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 ;这会在文本下方添加一个空白行,如果文本视图正下方有视觉上很重的控件,则可能看起来更好 .

  • 6

    以下内容就足够了:

    • 只需记住为 UITextView 设置 scrolling enabledNO

    enter image description here

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

    你甚至可以使用 UITableViewAutomaticDimension .

  • 1

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

    • 设置UITextView的高度约束 .
      enter image description here

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

    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtheightconstraints;
    

    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;
        }];
    
    }
    

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

  • 7

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

    [myTextView setDelegate: self];
    
    ...
    
    - (void)textViewDidChange:(UITextView *)textView {
      if (myTextView == textView) {
         // it changed.  Do resizing here.
      }
    }
    
  • 18

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

    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];
    
  • 1

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

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

    [_textView sizeToFit];
    

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

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

    希望这可能有所帮助..

  • 3

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

    • UITextView必须禁用滚动,您可以通过编程方式或通过界面构建器执行此操作 . 如果启用滚动,则不会调整大小,因为滚动可让您查看更大的内容 .

    • 在UITableViewController的viewDidLoad中,必须为estimatedRowHeight设置一个值,然后将 rowHeight 设置为 UITableViewAutomaticDimension .

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

    当我需要在适合特定区域的文本中创建文本时,这很有效:

    // The text must already be added to the subview, or contentviewsize will be wrong.
    
    - (void) reduceFontToFit: (UITextView *)tv {
        UIFont *font = tv.font;
        double pointSize = font.pointSize;
    
        while (tv.contentSize.height > tv.frame.size.height && pointSize > 7.0) {
            pointSize -= 1.0;
            UIFont *newFont = [UIFont fontWithName:font.fontName size:pointSize];
            tv.font = newFont;
        }
        if (pointSize != font.pointSize)
            NSLog(@"font down to %.1f from %.1f", pointSize, tv.font.pointSize);
    }
    
  • 1

    这是@jhibberd的快速版本

    let cell:MsgTableViewCell! = self.tableView.dequeueReusableCellWithIdentifier("MsgTableViewCell", forIndexPath: indexPath) as? MsgTableViewCell
        cell.msgText.text = self.items[indexPath.row]
        var fixedWidth:CGFloat = cell.msgText.frame.size.width
        var size:CGSize = CGSize(width: fixedWidth,height: CGFloat.max)
        var newSize:CGSize = cell.msgText.sizeThatFits(size)
        var newFrame:CGRect = cell.msgText.frame;
        newFrame.size = CGSizeMake(CGFloat(fmaxf(Float(newSize.width), Float(fixedWidth))), newSize.height);
        cell.msgText.frame = newFrame
        cell.msgText.frame.size = newSize        
        return cell
    
  • 6

    对于iOS 7.0,而不是将 frame.size.height 设置为 contentSize.height (当前无效)使用 [textView sizeToFit] .

    this question .

  • 1

    我查看了所有答案,并且都保持固定宽度并仅调整高度 . 如果您还想调整宽度,您可以非常轻松地使用此方法:

    所以在配置文本视图时,请设置滚动禁用

    textView.isScrollEnabled = false
    

    然后在委托方法 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)
    }
    

    输出:

    enter image description here

    enter image description here

  • 4

    禁用滚动

    添加constaints

    并添加你的文字

    [yourTextView setText:@"your text"];
    [yourTextView layoutIfNeeded];
    

    如果您使用 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;
    }
    
  • 3

    希望这可以帮助:

    - (void)textViewDidChange:(UITextView *)textView {
      CGSize textSize = textview.contentSize;
      if (textSize != textView.frame.size)
          textView.frame.size = textSize;
    }
    
  • 7

    如果有其他人到这里,这个解决方案适合我,1“Ronnie Liew”4“user63934”(我的文字来自网络服务):注意1000(在我的情况下没有什么可以这么大“)

    UIFont *fontNormal = [UIFont fontWithName:FONTNAME size:FONTSIZE];
    
    NSString *dealDescription = [client objectForKey:@"description"];
    
    //4
    CGSize textSize = [dealDescription sizeWithFont:fontNormal constrainedToSize:CGSizeMake(containerUIView.frame.size.width, 1000)];
    
    CGRect dealDescRect = CGRectMake(10, 300, containerUIView.frame.size.width, textSize.height);
    
    UITextView *dealDesc = [[[UITextView alloc] initWithFrame:dealDescRect] autorelease];
    
    dealDesc.text = dealDescription;
    //add the subview to the container
    [containerUIView addSubview:dealDesc];
    
    //1) after adding the view
    CGRect frame = dealDesc.frame;
    frame.size.height = dealDesc.contentSize.height;
    dealDesc.frame = frame;
    

    那就是......干杯

  • 12

    我发现根据文本大小重新调整UITextView高度的最佳方法 .

    CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0]
                           constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX)];
    

    或者你可以使用

    CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0]
                           constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX) lineBreakMode:NSLineBreakByTruncatingTail];
    
  • 1

    对于那些希望textview实际向上移动并保持底线位置的人

    CGRect frame = textView.frame;
    frame.size.height = textView.contentSize.height;
    
    if(frame.size.height > textView.frame.size.height){
        CGFloat diff = frame.size.height - textView.frame.size.height;
        textView.frame = CGRectMake(0, textView.frame.origin.y - diff, textView.frame.size.width, frame.size.height);
    }
    else if(frame.size.height < textView.frame.size.height){
        CGFloat diff = textView.frame.size.height - frame.size.height;
        textView.frame = CGRectMake(0, textView.frame.origin.y + diff, textView.frame.size.width, frame.size.height);
    }
    
  • 6

    唯一可行的代码是使用'SizeToFit'的那个,如上面的jhibberd答案,但实际上除非你在 ViewDidAppear 中调用它或将其连接到UITextView文本更改事件,否则它将不会被接收 .

  • 22

    基于Nikita Took的回答我来自Swift的以下解决方案在iOS 8上使用autolayout:

    descriptionTxt.scrollEnabled = false
        descriptionTxt.text = yourText
    
        var contentSize = descriptionTxt.sizeThatFits(CGSizeMake(descriptionTxt.frame.size.width, CGFloat.max))
        for c in descriptionTxt.constraints() {
            if c.isKindOfClass(NSLayoutConstraint) {
                var constraint = c as! NSLayoutConstraint
                if constraint.firstAttribute == NSLayoutAttribute.Height {
                    constraint.constant = contentSize.height
                    break
                }
            }
        }
    
  • 1

    Swift回答:以下代码计算textView的高度 .

    let maximumLabelSize = CGSize(width: Double(textView.frame.size.width-100.0), height: DBL_MAX)
                    let options = NSStringDrawingOptions.TruncatesLastVisibleLine | NSStringDrawingOptions.UsesLineFragmentOrigin
                    let attribute = [NSFontAttributeName: textView.font!]
                    let str = NSString(string: message)
                    let labelBounds = str.boundingRectWithSize(maximumLabelSize,
                        options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                        attributes: attribute,
                        context: nil)
                    let myTextHeight = CGFloat(ceilf(Float(labelBounds.height)))
    

    现在您可以将textView的高度设置为 myTextHeight

  • 87

    如果您需要在 staticTableView 中动态调整 textViewtableViewCell ,这是答案

    [https://stackoverflow.com/a/43137182/5360675][1]

相关问题