ios 如何根据其内容调整 UITextView 的大小?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/50467/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I size a UITextView to its content?
提问by drewh
Is there a good way to adjust the size of a UITextView
to conform to its content? Say for instance I have a UITextView
that contains one line of text:
有没有一种好的方法可以调整 a 的大小UITextView
以符合其内容?比如说我有一个UITextView
包含一行文本的内容:
"Hello world"
I then add another line of text:
然后我添加另一行文本:
"Goodbye world"
Is there a good way in Cocoa Touch to get the rect
that will hold all of the lines in the text view so that I can adjust the parent view accordingly?
Cocoa Touch 中是否有一个很好的方法来获取rect
文本视图中的所有行,以便我可以相应地调整父视图?
As another example, look at the notes' field for events in the Calendar application - note how the cell (and the UITextView
it contains) expands to hold all lines of text in the notes' string.
作为另一个示例,查看日历应用程序中事件的备注字段 - 注意单元格(及其UITextView
包含的单元格)如何扩展以容纳备注字符串中的所有文本行。
回答by jhibberd
This works for both iOS 6.1 and iOS 7:
这适用于 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;
}
Or in Swift (Works with Swift 4.1 in iOS 11)
或者在 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)
If you want support for iOS 6.1 then you should also:
如果您想要支持 iOS 6.1,那么您还应该:
textview.scrollEnabled = NO;
回答by Ronnie Liew
This no longer works on iOS 7 or above
这不再适用于 iOS 7 或更高版本
There is actually a very easy way to do resizing of the UITextView
to its correct height of the content. It can be done using the UITextView
contentSize
.
实际上有一种非常简单的方法可以将 调整为UITextView
正确的内容高度。可以使用UITextView
contentSize
.
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;
One thing to note is that the correct contentSize
is only available afterthe UITextView
has been added to the view with addSubview
. Prior to that it is equal to frame.size
有一点要注意的是,正确的contentSize
是唯一可用后的UITextView
已加入的观点addSubview
。在此之前它等于frame.size
This will not work if auto layout is ON. With auto layout, the general approach is to use the sizeThatFits
method and update the constant
value on a height constraint.
如果自动布局打开,这将不起作用。使用自动布局,一般方法是使用该sizeThatFits
方法并更新constant
高度约束上的值。
CGSize sizeThatShouldFitTheContent = [_textView sizeThatFits:_textView.frame.size];
heightConstraint.constant = sizeThatShouldFitTheContent.height;
heightConstraint
is a layout constraint that you typically setup via a IBOutlet by linking the property to the height constraint created in a storyboard.
heightConstraint
是一个布局约束,您通常通过 IBOutlet 通过将属性链接到故事板中创建的高度约束来设置。
Just to add to this amazing answer, 2014, if you:
只是为了补充这个惊人的答案,2014,如果你:
[self.textView sizeToFit];
there is a difference in behaviour with the iPhone6+only:
仅iPhone6+ 的行为有所不同:
With the 6+ only (not the 5s or 6) it does add "one more blank line" to the UITextView. The "RL solution" fixes this perfectly:
仅使用 6+(不是 5s 或 6),它确实向 UITextView 添加了“多一个空行”。“RL 解决方案”完美地解决了这个问题:
CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;
It fixes the "extra line" problem on 6+.
它修复了 6+ 上的“额外线路”问题。
回答by Brett Donald
To make a dynamically sizing UITextView
inside a UITableViewCell
, I found the following combination works in Xcode 6 with the iOS 8 SDK:
为了使动态上浆UITextView
里面UITableViewCell
,我发现在Xcode 6以下的组合可与iOS的8 SDK:
- Add a
UITextView
to aUITableViewCell
and constrain it to the sides - Set the
UITextView
'sscrollEnabled
property toNO
. With scrolling enabled, the frame of theUITextView
is independent of its content size, but with scrolling disabled, there is a relationship between the two. If your table is using the original default row height of 44 then it will automatically calculate row heights, but if you changed the default row height to something else, you may need to manually switch on auto-calculation of row heights in
viewDidLoad
:tableView.estimatedRowHeight = 150; tableView.rowHeight = UITableViewAutomaticDimension;
- 将 a 添加
UITextView
到 aUITableViewCell
并将其约束到两侧 - 将
UITextView
的scrollEnabled
属性设置为NO
. 启用滚动时, 的框架UITextView
与其内容大小无关,但禁用滚动时,两者之间存在关系。 如果您的表格使用原始默认行高 44,那么它会自动计算行高,但如果您将默认行高更改为其他内容,则可能需要手动打开行高的自动计算
viewDidLoad
:tableView.estimatedRowHeight = 150; tableView.rowHeight = UITableViewAutomaticDimension;
For read-only dynamically sizing UITextView
s, that's it. If you're allowing users to edit the text in your UITextView
, you also need to:
对于只读动态调整大小UITextView
,就是这样。如果您允许用户编辑 中的文本UITextView
,您还需要:
Implement the
textViewDidChange:
method of theUITextViewDelegate
protocol, and tell thetableView
to repaint itself every time the text is edited:- (void)textViewDidChange:(UITextView *)textView; { [tableView beginUpdates]; [tableView endUpdates]; }
And don't forget to set the
UITextView
delegate somewhere, either inStoryboard
or intableView:cellForRowAtIndexPath:
实现协议的
textViewDidChange:
方法UITextViewDelegate
,并告诉tableView
每次编辑文本时重新绘制自己:- (void)textViewDidChange:(UITextView *)textView; { [tableView beginUpdates]; [tableView endUpdates]; }
并且不要忘记将
UITextView
委托设置在某处,无论是 inStoryboard
还是 intableView:cellForRowAtIndexPath:
回答by Alok
回答by Juan Boero
Swift :
斯威夫特:
textView.sizeToFit()
回答by user63934
In my (limited) experience,
在我(有限的)经验中,
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
does not respect newline characters, so you can end up with a lot shorter CGSize
than is actually required.
不尊重换行符,因此最终可能CGSize
比实际需要的要短得多。
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
does seem to respect the newlines.
似乎确实尊重换行符。
Also, the text isn't actually rendered at the top of the UITextView
. In my code, I set the new height of the UITextView
to be 24 pixels larger than the height returned by the sizeOfFont
methods.
此外,文本实际上并未呈现在UITextView
. 在我的代码中,我将 的新高度设置为UITextView
比sizeOfFont
方法返回的高度大 24 像素。
回答by phatmann
In iOS6, you can check the contentSize
property of UITextView right after you set the text. In iOS7, this will no longer work. If you want to restore this behavior for iOS7, place the following code in a subclass of UITextView.
在 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;
}
}
回答by Nikita Took
I will post right solution at the bottom of the page in case someone is brave (or despaired enough) to read to this point.
我会在页面底部发布正确的解决方案,以防有人勇敢(或足够绝望)读到这里。
Here is gitHub repo for those, who don't want to read all that text: resizableTextView
这是 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.Short and elegant solution.
这适用于 iOs7(我相信它适用于 iOs8)和自动布局。你不需要幻数,禁用布局和类似的东西。简短而优雅的解决方案。
I think, that all constraint-related code should go to updateConstraints
method. So, let's make our own ResizableTextView
.
我认为,所有与约束相关的代码都应该转到updateConstraints
方法。所以,让我们自己制作ResizableTextView
.
The first problem we meet here is that don't know real content size before viewDidLoad
method. We can take long and buggy road and calculate it based on font size, line breaks, etc. But we need robust solution, so we'll do:
我们在这里遇到的第一个问题是在viewDidLoad
方法之前不知道实际内容大小。我们可以走很长的路,并根据字体大小、换行符等来计算它。但是我们需要强大的解决方案,所以我们会这样做:
CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];
CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];
So now we know real contentSize no matter where we are: before or after viewDidLoad
. Now add height constraint on textView (via storyboard or code, no matter how). We'll adjust that value with our contentSize.height
:
所以现在我们知道真正的 contentSize 无论我们在哪里: before 或 after viewDidLoad
。现在在 textView 上添加高度约束(通过故事板或代码,无论如何)。我们将使用我们的 来调整该值contentSize.height
:
[self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
if (constraint.firstAttribute == NSLayoutAttributeHeight) {
constraint.constant = contentSize.height;
*stop = YES;
}
}];
The last thing to do is to tell superclass to updateConstraints
.
最后要做的是告诉超类到updateConstraints
.
[super updateConstraints];
Now our class looks like:
现在我们的类看起来像:
ResizableTextView.m
可调整大小的TextView.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];
}
Pretty and clean, right? And you don't have to deal with that code in your controllers!
漂亮干净,对吧?而且您不必在控制器中处理该代码!
But wait!Y NO ANIMATION!
可是等等!Y 没有动画!
You can easily animate changes to make textView
stretch smoothly. Here is an example:
您可以轻松地为更改设置动画以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];
回答by Mike McMaster
Did you try [textView sizeThatFits:textView.bounds]
?
你试了[textView sizeThatFits:textView.bounds]
吗?
Edit: sizeThatFits returns the size but does not actually resize the component. I'm not sure if that's what you want, or if [textView sizeToFit]
is more what you were looking for. In either case, I do not know if it will perfectly fit the content like you want, but it's the first thing to try.
编辑:sizeThatFits 返回大小,但实际上并不调整组件的大小。我不确定这是否是您想要的,还是[textView sizeToFit]
您正在寻找的更多。在任何一种情况下,我都不知道它是否会像您想要的那样完美契合内容,但这是首先要尝试的。
回答by Code Addict
Another method is the find the size a particular string will take up using the NSString
method:
另一种方法是使用以下NSString
方法查找特定字符串将占用的大小:
-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
This returns the size of the rectangle that fits the given string with the given font. Pass in a size with the desired width and a maximum height, and then you can look at the height returned to fit the text. There is a version that lets you specify line break mode also.
这将返回适合具有给定字体的给定字符串的矩形的大小。传入具有所需宽度和最大高度的大小,然后您可以查看返回的高度以适合文本。还有一个版本可以让您指定换行模式。
You can then use the returned size to change the size of your view to fit.
然后,您可以使用返回的大小来更改视图的大小以适合。