How do I size a UITextView to its content?
有没有一种很好的方法来调整
1 | "Hello world" |
然后我添加另一行文字:
1 | "Goodbye world" |
在Cocoa Touch中有一个很好的方法来获取
再举一个例子,查看日历应用程序中事件的注释字段 - 注意单元格(及其包含的
这适用于iOS 6.1和iOS 7:
1 2 3 4 5 6 7 8 | - (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一起使用)
1 2 3 | 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,那么您还应该:
1 | textview.scrollEnabled = NO; |
这不再适用于iOS 7或更高版本
实际上有一种非常简单的方法可以将
1 2 3 | CGRect frame = _textView.frame; frame.size.height = _textView.contentSize.height; _textView.frame = frame; |
需要注意的一点是,只有在使用
如果自动布局为ON,则无效。对于自动布局,一般方法是使用
1 2 | CGSize sizeThatShouldFitTheContent = [_textView sizeThatFits:_textView.frame.size]; heightConstraint.constant = sizeThatShouldFitTheContent.height; |
只是为了增加这个惊人的答案,2014年,如果你:
1 | [self.textView sizeToFit]; |
仅与iPhone6 +的行为有所不同:
只有6+(不是5s或6),它确实为UITextView增加了"一个空行"。"RL解决方案"完美地解决了这个问题:
1 2 3 | CGRect _f = self.mainPostText.frame; _f.size.height = self.mainPostText.contentSize.height; self.mainPostText.frame = _f; |
它修复了6+上的"额外线"问题。
要在
-
将
UITextView 添加到UITableViewCell 并将其约束到两侧 -
将
UITextView 的scrollEnabled 属性设置为NO 。启用滚动后,UITextView 的框架与其内容大小无关,但在禁用滚动的情况下,两者之间存在关系。 -
如果您的表使用原始默认行高44,那么它将自动计算行高,但如果您将默认行高更改为其他行,则可能需要在
viewDidLoad 中手动启用行高的自动计算:1
2tableView.estimatedRowHeight = 150;
tableView.rowHeight = UITableViewAutomaticDimension;
对于只读动态调整大小
-
实现
UITextViewDelegate 协议的textViewDidChange: 方法,并告诉tableView 每次编辑文本时重绘自身:1
2
3
4
5- (void)textViewDidChange:(UITextView *)textView;
{
[tableView beginUpdates];
[tableView endUpdates];
} -
并且不要忘记在
Storyboard 或tableView:cellForRowAtIndexPath: 中将UITextView 委托设置在某处
使用代码和故事板的非常简单的工作解决方案。
按代码
1 | textView.scrollEnabled = false |
通过故事板
取消选中滚动启用
除此之外无需做任何事情。
斯威夫特:
1 | textView.sizeToFit() |
在我(有限)的经历中,
1 | - (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode |
不尊重换行符,因此最终可能会比实际需要的短
1 | - (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size |
似乎确实尊重新线。
此外,文本实际上并未呈现在
在iOS6中,您可以在设置文本后立即检查UITextView的
1 2 3 4 5 6 7 8 9 10 | - (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 repo,他们不想阅读所有文本:resizableTextView
这适用于iOs7(我相信它适用于iOs8)和自动布局。你不需要魔术数字,禁用布局和类似的东西。简洁优雅的解决方案。
我认为,所有与约束相关的代码都应该转到
我们在这里遇到的第一个问题是在
<5233>
所以现在我们知道真实的contentSize,无论我们在哪里:在
1 2 3 4 5 6 | [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) { if (constraint.firstAttribute == NSLayoutAttributeHeight) { constraint.constant = contentSize.height; *stop = YES; } }]; |
最后要做的是告诉超类
1 | [super updateConstraints]; |
现在我们的班级看起来像:
ResizableTextView.m
1 2 3 4 5 6 7 8 9 10 11 12 | - (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]; } |
漂亮干净吧?而且您不必在控制器中处理该代码!
可是等等!
你没动画!
您可以轻松地对更改进行动画处理,以使
1 2 3 4 5 6 7 8 | [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]; |
你试过
编辑:sizeThatFits返回大小但实际上并未调整组件大小。我不确定这是否是您想要的,或者
另一种方法是使用
这将返回适合给定字符串的矩形的大小。传递具有所需宽度和最大高度的大小,然后您可以查看返回的高度以适合文本。有一个版本可以让你指定换行模式。
然后,您可以使用返回的大小来更改视图的大小以适应。
如果您没有方便的
1 2 3 4 5 6 | 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只是一个非常大的最大尺寸。
在实践中,您可能希望在高度上添加额外的
我们可以通过约束来实现。

2.为该高度约束创建IBOutlet。
1 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtheightconstraints; |
3.不要忘记为你的textview设置委托。
4。
1 2 3 4 5 6 7 8 9 10 11 12 | -(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; }]; } |
然后像这样更新你的约束:)
以下内容就足够了:
你甚至可以使用
从iOS 8开始,可以使用UITableView的自动布局功能自动调整UITextView的大小,而根本不需要自定义代码。我已经在github上放了一个项目来演示这个,但是关键是:
1 2 3 4 5 | - (void)viewDidLoad { [super viewDidLoad]; self.tableView.estimatedRowHeight = self.tableView.rowHeight; self.tableView.rowHeight = UITableViewAutomaticDimension; } |
使用自动布局和你的sizetofit的人不起作用,请检查你的宽度约束一次。如果您错过了宽度约束,那么高度将是准确的。
无需使用任何其他API。只需一行即可解决所有问题。
1 | [_textView sizeToFit]; |
在这里,我只关心高度,保持宽度固定,并错过了我的TextView在故事板中的宽度约束。
这是为了显示来自服务的动态内容。
希望这可能有所帮助..
结合Mike McMaster的回答,您可能希望做以下事情:
1 2 3 4 5 6 7 8 9 | [myTextView setDelegate: self]; ... - (void)textViewDidChange:(UITextView *)textView { if (myTextView == textView) { // it changed. Do resizing here. } } |
我找到了一种方法来根据文本字段内的文本调整文本字段的高度,并根据文本字段的高度在其下方排列标签!这是代码。
1 2 3 4 5 6 7 8 9 10 11 12 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 | // 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的快速版本
1 2 3 4 5 6 7 8 9 10 | 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 |
我查看了所有答案,并且都保持固定宽度并仅调整高度。如果你想调整宽度,你可以很容易地使用这种方法:
所以在配置文本视图时,请设置滚动禁用
1 | textView.isScrollEnabled = false |
然后在委托方法
1 2 3 4 | func textViewDidChange(_ textView: UITextView) { let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)) textView.frame = CGRect(origin: textView.frame.origin, size: newSize) } |
输出:
禁用滚动
1 2 | [yourTextView setText:@"your text"]; [yourTextView layoutIfNeeded]; |
如果您使用
1 2 3 4 5 6 7 8 9 10 | [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,不要将
看到这个问题。
如果有其他人到这里,这个解决方案适合我,1"Ronnie Liew"+4"user63934"(我的文字来自网络服务):
注意1000(在我的情况下没有什么可以这么大")
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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高度的最佳方法。
1 2 | CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0] constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX)]; |
或者你可以使用
1 2 | CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0] constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX) lineBreakMode:NSLineBreakByTruncatingTail]; |
希望这可以帮助:
1 2 3 4 5 | - (void)textViewDidChange:(UITextView *)textView { CGSize textSize = textview.contentSize; if (textSize != textView.frame.size) textView.frame.size = textSize; } |
对于那些希望textview实际向上移动并保持底线位置的人
1 2 3 4 5 6 7 8 9 10 11 | 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答案,但实际上除非你在ViewDidAppear中调用它或将其连接到UITextView文本更改事件,否则它将无法获取。
基于Nikita Took的回答,我在Swift中找到了以下解决方案,该解决方案适用于iOS 8的自动布局:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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的高度。
1 2 3 4 5 6 7 8 9 | 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的高度设置为
如果您需要在
[https://stackoverflow.com/a/43137182/5360675][1]
就像ios 11上的魅力一样
我正在一个小区工作,就像一个带泡泡的聊天室。
1 2 3 4 5 6 7 8 9 10 11 | let content = UITextView(frame: CGRect(x: 4, y: 4, width: 0, height: 0)) content.text ="what ever short or long text you wanna try" content.textAlignment = NSTextAlignment.left content.font = UIFont.systemFont(ofSize: 13) let spaceAvailable = 200 //My cell is fancy I have to calculate it... let newSize = content.sizeThatFits(CGSize(width: CGFloat(spaceAvailable), height: CGFloat.greatestFiniteMagnitude)) content.isEditable = false content.dataDetectorTypes = UIDataDetectorTypes.all content.isScrollEnabled = false content.backgroundColor = UIColor.clear bkgView.addSubview(content) |
这种方法似乎适用于ios7
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | // 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:@" "]) { [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; } } |
Key Value Observing(KVO)非常简单,只需创建UITextView的子类即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private func setup() { // Called from init or somewhere fitToContentObservations = [ textView.observe(\.contentSize) { _, _ in self.invalidateIntrinsicContentSize() }, // For some reason the content offset sometimes is non zero even though the frame is the same size as the content size. textView.observe(\.contentOffset) { _, _ in if self.contentOffset != .zero { // Need to check this to stop infinite loop self.contentOffset = .zero } } ] } public override var intrinsicContentSize: CGSize { return contentSize } |
如果您不想继承子类,可以尝试在
询问
注意
使用
当你使用大小类和
为了克服这个问题,我发现有用的是覆盖单元格的
如果您使用的是scrollview和内容视图,并且希望根据TextView内容高度增加高度,那么这段代码将对您有所帮助。
希望这会有所帮助,它在iOS9.2中完美运行
当然设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | -(void)adjustHeightOfTextView { //this pieces of code will helps to adjust the height of the uitextview View W.R.T content //This block of code work will calculate the height of the textview text content height and calculate the height for the whole content of the view to be displayed.Height --;gt; 400 is fixed,it will change if you change anything in the storybord. CGSize textViewSize = [self.textview sizeThatFits:CGSizeMake(self.view.frame.size.width, self.view.frame.size.height)];//calulcate the content width and height float textviewContentheight =textViewSize.height; self.scrollview.contentSize = CGSizeMake(self.textview.frame.size.width,textviewContentheight + 400);//height value is passed self.scrollview.frame =CGRectMake(self.scrollview.frame.origin.x, self.scrollview.frame.origin.y, self.scrollview.frame.size.width, textviewContentheight+400); CGRect Frame = self.contentview.frame; Frame.size.height = textviewContentheight + 400; [self.contentview setFrame:Frame]; self.textview.frame =CGRectMake(self.textview.frame.origin.x, self.textview.frame.origin.y, self.textview.frame.size.width, textviewContentheight); [ self.textview setContentSize:CGSizeMake( self.textview.frame.size.width,textviewContentheight)]; self.contenview_heightConstraint.constant = self.scrollview.bounds.size.height; NSLog(@"%f",self.contenview_heightConstraint.constant); } |
这是步骤
解决方案适用于所有版本的iOS。 Swift 3.0及以上版本。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | //1. Add your UITextView in ViewDidLoad let textView = UITextView() textView.frame = CGRect(x: 0, y: 0, width: 200, height: 100) textView.backgroundColor = .lightGray textView.text ="Here is some default text." //2. Add constraints textView.translatesAutoresizingMaskIntoConstraints = false [ textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), textView.leadingAnchor.constraint(equalTo: view.leadingAnchor), textView.trailingAnchor.constraint(equalTo: view.trailingAnchor), textView.heightAnchor.constraint(equalToConstant: 50), textView.widthAnchor.constraint(equalToConstant: 30) ].forEach{ $0.isActive = true } textView.font = UIFont.preferredFont(forTextStyle: .headline) textView.delegate = self textView.isScrollEnabled = false textViewDidChange(textView) //3. Implement the delegate method. func textViewDidChange(_ textView: UITextView) { let size = CGSize(width: view.frame.width, height: .infinity) let estimatedSize = textView.sizeThatFits(size) textView.constraints.forEach { (constraint) in if constraint.firstAttribute == .height { print("Height:", estimatedSize.height) constraint.constant = estimatedSize.height } } } |
不确定为什么人们总是过于复杂化:
这里是 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | - (void)textViewDidChange:(UITextView *)textView{ CGRect frame = textView.frame; CGFloat height = [self measureHeightOfUITextView:textView]; CGFloat insets = textView.textContainerInset.top + textView.textContainerInset.bottom; height += insets; frame.size.height = height; if(frame.size.height > textView.frame.size.height){ CGFloat diff = frame.size.height - textView.frame.size.height; textView.frame = CGRectMake(5, 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(5, textView.frame.origin.y + diff, textView.frame.size.width, frame.size.height); } [textView setNeedsDisplay]; } |