首先,需要注意的是,UITextView 和 UILabel 在文本呈现方式上存在很大差异。 UITextView 不仅所有边框都有 insets,而且里面的文字布局也略有不同。
因此,sizeWithFont: 对于 UITextViews 来说是个坏方法。
而UITextView 本身有一个名为sizeThatFits: 的函数,它将返回在您可以指定的边界框内显示UITextView 的所有内容所需的最小尺寸。
以下内容同样适用于 iOS 7 和更早版本,并且目前不包含任何已弃用的方法。
简单的解决方案
- (CGFloat)textViewHeightForAttributedText: (NSAttributedString*)text andWidth: (CGFloat)width {
UITextView *calculationView = [[UITextView alloc] init];
[calculationView setAttributedText:text];
CGSize size = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return size.height;
}
此函数将采用 NSAttributedString 和所需的宽度作为 CGFloat 并返回所需的高度
详细解决方案
由于我最近做了类似的事情,我想我也会分享一些我遇到的相关问题的解决方案。我希望它会对某人有所帮助。
这更深入,将涵盖以下内容:
- 当然:根据显示包含的
UITextView 的全部内容所需的大小设置UITableViewCell 的高度
- 响应文本变化(并为行的高度变化设置动画)
- 在编辑时调整
UITableViewCell 的大小时,将光标保持在可见区域内并将第一响应者保持在 UITextView 上
如果您使用的是静态表格视图,或者您只有已知数量的UITextViews,您可以使第 2 步更简单。
1。首先,覆盖heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// check here, if it is one of the cells, that needs to be resized
// to the size of the contained UITextView
if ( )
return [self textViewHeightForRowAtIndexPath:indexPath];
else
// return your normal height here:
return 100.0;
}
2。定义计算所需高度的函数:
将NSMutableDictionary(在此示例中称为textViews)作为实例变量添加到您的UITableViewController 子类。
使用此字典存储对个人 UITextViews 的引用,如下所示:
(是的,indexPaths are valid keys for dictionaries)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Do you cell configuring ...
[textViews setObject:cell.textView forKey:indexPath];
[cell.textView setDelegate: self]; // Needed for step 3
return cell;
}
这个函数现在将计算实际高度:
- (CGFloat)textViewHeightForRowAtIndexPath: (NSIndexPath*)indexPath {
UITextView *calculationView = [textViews objectForKey: indexPath];
CGFloat textViewWidth = calculationView.frame.size.width;
if (!calculationView.attributedText) {
// This will be needed on load, when the text view is not inited yet
calculationView = [[UITextView alloc] init];
calculationView.attributedText = // get the text from your datasource add attributes and insert here
textViewWidth = 290.0; // Insert the width of your UITextViews or include calculations to set it accordingly
}
CGSize size = [calculationView sizeThatFits:CGSizeMake(textViewWidth, FLT_MAX)];
return size.height;
}
3。在编辑时启用调整大小
对于接下来的两个函数,重要的是UITextViews 的委托设置为您的UITableViewController。如果您需要其他东西作为委托,您可以通过从那里进行相关调用或使用适当的 NSNotificationCenter 挂钩来解决它。
- (void)textViewDidChange:(UITextView *)textView {
[self.tableView beginUpdates]; // This will cause an animated update of
[self.tableView endUpdates]; // the height of your UITableViewCell
// If the UITextView is not automatically resized (e.g. through autolayout
// constraints), resize it here
[self scrollToCursorForTextView:textView]; // OPTIONAL: Follow cursor
}
4。编辑时跟随光标
- (void)textViewDidBeginEditing:(UITextView *)textView {
[self scrollToCursorForTextView:textView];
}
这将使UITableView滚动到光标的位置,如果它不在UITableView的可见矩形内:
- (void)scrollToCursorForTextView: (UITextView*)textView {
CGRect cursorRect = [textView caretRectForPosition:textView.selectedTextRange.start];
cursorRect = [self.tableView convertRect:cursorRect fromView:textView];
if (![self rectVisible:cursorRect]) {
cursorRect.size.height += 8; // To add some space underneath the cursor
[self.tableView scrollRectToVisible:cursorRect animated:YES];
}
}
5。通过设置插图调整可见矩形
编辑时,您的UITableView 的部分内容可能会被键盘覆盖。如果 tableviews insets 没有调整,scrollToCursorForTextView: 将无法滚动到您的光标,如果它位于 tableview 的底部。
- (void)keyboardWillShow:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(self.tableView.contentInset.top, 0.0, kbSize.height, 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
}
- (void)keyboardWillHide:(NSNotification*)aNotification {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.35];
UIEdgeInsets contentInsets = UIEdgeInsetsMake(self.tableView.contentInset.top, 0.0, 0.0, 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
[UIView commitAnimations];
}
最后一部分:
在您的视图中确实加载了,通过NSNotificationCenter 注册键盘更改通知:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
请不要生我的气,因为我回答了这么久。虽然不是所有问题都需要回答这个问题,但我相信这些直接相关的问题会对其他人有所帮助。
更新:
正如 Dave Haupert 指出的,我忘记包含 rectVisible 函数:
- (BOOL)rectVisible: (CGRect)rect {
CGRect visibleRect;
visibleRect.origin = self.tableView.contentOffset;
visibleRect.origin.y += self.tableView.contentInset.top;
visibleRect.size = self.tableView.bounds.size;
visibleRect.size.height -= self.tableView.contentInset.top + self.tableView.contentInset.bottom;
return CGRectContainsRect(visibleRect, rect);
}
我还注意到,scrollToCursorForTextView: 仍然包含对我项目中的一个 TextField 的直接引用。如果您对找不到bodyTextView 有问题,请检查该函数的更新版本。