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

"Hello world"

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

"Goodbye world"

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

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


当前回答

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

这里是那些gitHub回购,谁不想读所有的文本:resizableTextView

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

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

其他回答

这个方法似乎适用于ios7

 // Code from apple developer forum - @Steve Krulewitz, @Mark Marszal, @Eric Silverberg
- (CGFloat)measureHeight
{
    if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
    {
    CGRect frame = internalTextView.bounds;
    CGSize fudgeFactor;
    // The padding added around the text on iOS6 and iOS7 is different.
    fudgeFactor = CGSizeMake(10.0, 16.0);

    frame.size.height -= fudgeFactor.height;
    frame.size.width -= fudgeFactor.width;

    NSMutableAttributedString* textToMeasure;
    if(internalTextView.attributedText && internalTextView.attributedText.length > 0){
        textToMeasure = [[NSMutableAttributedString alloc] initWithAttributedString:internalTextView.attributedText];
    }
    else{
        textToMeasure = [[NSMutableAttributedString alloc] initWithString:internalTextView.text];
        [textToMeasure addAttribute:NSFontAttributeName value:internalTextView.font range:NSMakeRange(0, textToMeasure.length)];
    }

    if ([textToMeasure.string hasSuffix:@"\n"])
    {
        [textToMeasure appendAttributedString:[[NSAttributedString alloc] initWithString:@"-" attributes:@{NSFontAttributeName: internalTextView.font}]];
    }

    // NSAttributedString class method: boundingRectWithSize:options:context is
    // available only on ios7.0 sdk.
    CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
                                              options:NSStringDrawingUsesLineFragmentOrigin
                                              context:nil];

    return CGRectGetHeight(size) + fudgeFactor.height;
}
else
{
    return self.internalTextView.contentSize.height;
}
}

你试过[textView sizeThatFits:textView. txt]吗?范围)?

编辑:sizeThatFits返回大小,但并不实际调整组件的大小。我不确定如果这是你想要的,或者如果[textView sizeToFit]是更多的你要寻找的。无论哪种情况,我不知道它是否完全适合你想要的内容,但这是第一件要尝试的事情。

如果有其他人来这里,这个解决方案为我工作,1“Ronnie Liew”+4“user63934”(我的文本从web服务到达): 注意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;

那就是……干杯

对我来说最简单的解决方案是在Storyboard的textView上放一个高度约束,然后将textView和高度约束连接到代码:

@IBOutlet var myAwesomeTextView: UITextView!
@IBOutlet var myAwesomeTextViewHeight: NSLayoutConstraint!

然后在设置文本和段落样式后,在viewDidAppear中添加这个:

self.myAwesomeTextViewHeight.constant = self.myAwesomeTextView.contentSize.height

一些注意事项:

与其他解决方案相比,必须将isScrollEnabled设置为true才能使其工作。 在我的例子中,我在代码中设置自定义属性的字体,因此我必须在viewDidAppear中设置高度(在此之前它不会正常工作)。如果你没有在代码中更改任何文本属性,你应该能够在viewDidLoad或设置文本后的任何地方设置高度。

基于Nikita Took的回答,我想出了以下解决方案,适用于iOS 8的自动布局:

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