如何根据其内容调整 UITextView 的大小?
-
09-06-2019 - |
题
有没有好的办法调整a的大小 UITextView
以符合其内容?比如说我有一个 UITextView
包含一行文本:
"Hello world"
然后我添加另一行文本:
"Goodbye world"
Cocoa Touch 有没有好的方法来获取 rect
这将保留文本视图中的所有行,以便我可以相应地调整父视图?
作为另一个示例,查看日历应用程序中事件的注释字段 - 请注意单元格(以及 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;
}
或者在 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;
其他提示
这不再适用于 iOS 7 或更高版本
实际上有一种非常简单的方法可以调整大小 UITextView
到内容的正确高度。可以使用以下方法完成 UITextView
contentSize
.
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 设置该约束,方法是将属性链接到故事板中创建的高度约束。
只是为了补充这个令人惊奇的答案,2014 年,如果您:
[self.textView sizeToFit];
行为上与 iPhone6+ 仅有的:
仅对于 6+(不是 5s 或 6),它确实向 UITextView 添加了“一个空行”。“RL 解决方案”完美地解决了这个问题:
CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;
它修复了 6+ 上的“额外线路”问题。
进行动态调整大小 UITextView
里面一个 UITableViewCell
, ,我发现以下组合在 Xcode 6 和 iOS 8 SDK 中有效:
- 添加一个
UITextView
到一个UITableViewCell
并将其限制在两侧 - 设置
UITextView
的scrollEnabled
财产给NO
. 。启用滚动后,框架UITextView
与其内容大小无关,但在禁用滚动的情况下,两者之间存在关系。 如果您的表使用原始默认行高 44,那么它将自动计算行高,但如果您将默认行高更改为其他值,则可能需要手动打开自动计算行高
viewDidLoad
:tableView.estimatedRowHeight = 150; tableView.rowHeight = UITableViewAutomaticDimension;
用于只读动态调整大小 UITextView
s,就是这样。如果您允许用户编辑您的文本 UITextView
, ,您还需要:
实施
textViewDidChange:
的方法UITextViewDelegate
协议,并告诉tableView
每次编辑文本时重新绘制自身:- (void)textViewDidChange:(UITextView *)textView; { [tableView beginUpdates]; [tableView endUpdates]; }
并且不要忘记设置
UITextView
委托某处,无论是在Storyboard
或在tableView:cellForRowAtIndexPath:
斯威夫特:
textView.sizeToFit()
根据我(有限的)经验,
- (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 的属性。在 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;
}
}
我将在页面底部发布正确的解决方案,以防有人勇敢(或足够绝望)阅读到这一点。
这是 gitHub 存储库,适合那些不想阅读所有文本的人: 可调整大小的文本视图
这适用于 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;
}
}];
最后要做的事情是告诉超类 updateConstraints
.
[super updateConstraints];
现在我们的类看起来像:
可调整大小的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];
}
漂亮又干净,对吧?而且您不必在您的代码中处理该代码 控制器!
可是等等! 没有动画!
您可以轻松地以动画方式进行更改 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];
你试过了吗 [textView sizeThatFits:textView.bounds]
?
编辑:sizeThatFits 返回尺寸,但实际上并不调整组件的大小。我不确定这是否是你想要的,或者 [textView sizeToFit]
更符合您的需求。无论哪种情况,我不知道它是否完全适合您想要的内容,但这是首先要尝试的事情。
另一种方法是使用以下命令查找特定字符串将占用的大小 NSString
方法:
-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
这将返回适合给定字符串和给定字体的矩形的大小。传入具有所需宽度和最大高度的尺寸,然后您可以查看返回的高度以适合文本。还有一个版本可以让您指定换行模式。
然后,您可以使用返回的大小来更改视图的大小以适应。
如果您没有 UITextView
方便(例如,您正在调整表格视图单元格的大小),您必须通过测量字符串来计算大小,然后考虑每侧的 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;
这里,每个 8 占四个填充边缘之一,而 100000 只是一个非常大的最大尺寸。
在实践中,您可能需要添加一个额外的 font.leading
到高度;这会在文本下方添加一个空行,如果文本视图正下方有视觉上较重的控件,则该空行可能看起来更好。
我们可以通过约束来做到这一点。
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;
}];
}
然后像这样更新你的约束:)
结合迈克·麦克马斯特的回答,您可能想做类似的事情:
[myTextView setDelegate: self];
...
- (void)textViewDidChange:(UITextView *)textView {
if (myTextView == textView) {
// it changed. Do resizing here.
}
}
我找到了一种方法,可以根据文本字段中的文本调整文本字段的高度,并根据文本字段的高度在其下方排列标签!这是代码。
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];
使用自动布局并且您的 sizetofit 不起作用的人,请检查一次您的宽度限制。如果您错过了宽度约束,那么高度将是准确的。
无需使用任何其他 API。只需一行即可解决所有问题。
[_textView sizeToFit];
在这里,我只关心高度,保持宽度固定,并且错过了故事板中 TextView 的宽度约束。
这是为了显示服务的动态内容。
希望这可能有所帮助..
从 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 或更高版本。
当我需要在 a 中制作文本时,这非常有效 UITextView
适合特定区域:
// 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); }
这是 @jhibberd 的 swift 版本
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
我查看了所有答案,所有答案都保持固定宽度并仅调整高度。如果您还想调整宽度,您可以非常轻松地使用此方法:
因此,在配置文本视图时,请设置滚动禁用
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)
}
输出:
禁用滚动
添加约束
并添加您的文字
[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;
}
对于 iOS 7.0,无需设置 frame.size.height
到 contentSize.height
(目前什么也不做)使用 [textView sizeToFit]
.
看 这个问题.
希望这可以帮助:
- (void)textViewDidChange:(UITextView *)textView {
CGSize textSize = textview.contentSize;
if (textSize != textView.frame.size)
textView.frame.size = textSize;
}
如果有其他人到达这里,这个解决方案对我有用,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;
那就是...干杯
我发现根据文本大小重新调整 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];
对于那些希望 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);
}
唯一有效的代码是使用“SizeToFit”的代码,如上面 jhibberd 答案中所示,但实际上它不会拾取,除非您调用它 查看已出现 或将其连接到 UITextView 文本更改事件。
根据 Nikita Take 的回答,我在 Swift 中找到了以下解决方案,它可以在 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
}
}
}
迅速回答:以下代码计算 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
如果您需要调整大小,这是答案 textView
和 tableViewCell
动态地在 staticTableView