在 iOS7中带有 UITextView 高度的 UITableViewCell?

在 iOS7中,如何计算带有 UITextView 的 UITableViewCell 的高度?

我找到了很多类似问题的答案,但 sizeWithFont:参与了每个解决方案,这种方法是不被推崇的!

我知道我必须使用 - (CGFloat)tableView:heightForRowAtIndexPath:,但我如何计算我的 TextView 需要显示整个文本的高度?

90972 次浏览
UITextView *txtDescLandscape=[[UITextView alloc] initWithFrame:CGRectMake(2,20,310,2)];


txtDescLandscape.editable =NO;
txtDescLandscape.textAlignment =UITextAlignmentLeft;
[txtDescLandscape setFont:[UIFont fontWithName:@"ArialMT" size:15]];
txtDescLandscape.text =[objImage valueForKey:@"imgdescription"];
txtDescLandscape.text =[txtDescLandscape.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[txtDescLandscape sizeToFit];
[headerView addSubview:txtDescLandscape];


CGRect txtViewlandscpframe = txtDescLandscape.frame;
txtViewlandscpframe.size.height = txtDescLandscape.contentSize.height;
txtDescLandscape.frame = txtViewlandscpframe;

我认为这种方法可以计算文本视图的高度,然后根据高度调整表格视图单元格的大小,这样就可以在单元格上显示全文

有一个新的函数可以替换 sizeWithFont,该函数是 bound ingRectWithSize。

我在我的项目中添加了以下功能,它利用了 iOS7上的新功能和小于7的 iOS 上的旧功能。它的语法与 sizeWithFont 基本相同:

    -(CGSize)text:(NSString*)text sizeWithFont:(UIFont*)font constrainedToSize:(CGSize)size{
if(IOS_NEWER_OR_EQUAL_TO_7){
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
nil];


CGRect frame = [text boundingRectWithSize:size
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:attributesDictionary
context:nil];


return frame.size;
}else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [text sizeWithFont:font constrainedToSize:size];
#pragma clang diagnostic pop
}
}

您可以在项目的 prefix.pch 文件中添加 IOS _ NEWER _ OR _ EQUAL _ TO _ 7,如下所示:

#define IOS_NEWER_OR_EQUAL_TO_7 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 7.0 )

首先,需要注意的是,当涉及到如何呈现文本时,UITextView 和 UILabel 之间有很大的区别。UITextView 不仅在所有边框上都有插入,而且其中的文本布局略有不同。

因此,对于 UITextViewssizeWithFont:是一种糟糕的方法。

相反,UITextView本身有一个称为 sizeThatFits:的函数,它将返回在一个可指定的边界框中显示 UITextView的所有内容所需的最小大小。

以下内容将同样适用于 iOS7和更老的版本,目前不包括任何已经过时的方法。


简单解决方案

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

如果使用的是静态表视图,或者只有已知数量的 UITextView,那么可以使步骤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的引用,如下所示:

(是的,IndexPath 是字典的有效键)

- (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. Enable Resizing while Editing

对于接下来的两个函数,重要的是将 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
}

编辑时跟随光标

- (void)textViewDidBeginEditing:(UITextView *)textView {
[self scrollToCursorForTextView:textView];
}

This will make the UITableView scroll to the position of the cursor, if it is not inside the visible Rect of the 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. 通过设置插图调整可见直接

While editing, parts of your UITableView may be covered by the Keyboard. If the tableviews insets are not adjusted, scrollToCursorForTextView: will not be able to scroll to your cursor, if it is at the bottom of the 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:仍然直接引用了我的项目中的一个 TextFields。如果找不到 bodyTextView,请检查函数的更新版本。

如果您正在使用自动布局,一种方法是让自动布局引擎为您计算大小。这不是最有效的方法,但是非常方便(可以说是最准确的)。随着单元格布局复杂度的增加,它变得更加方便——例如,突然在单元格中有两个或更多的文本视图/字段。

我用一个使用自动布局调整表格视图单元格大小的完整示例回答了一个类似的问题,在这里:

How to resize superview to fit all subviews with autolayout?

Tim Bodeit 的回答很棒。我使用简单解决方案的代码来正确获得文本视图的高度,并在 heightForRowAtIndexPath中使用该高度。但我没有使用其余的答案来调整文本视图的大小。相反,我编写代码来更改 cellForRowAtIndexPath中文本视图的 frame

在 iOS6及以下版本中一切正常,但在 iOS7中,文本视图中的文本无法完全显示,即使文本视图的 frame确实被调整了大小。(我没有使用 Auto Layout)。这就是为什么 iOS7中有 TextKit,而文本的位置是由 UITextView中的 NSTextContainer控制的。因此,在我的例子中,我需要添加一行来设置 someTextView,以便使它在 iOS7中正确工作。

    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) {
someTextView.textContainer.heightTracksTextView = YES;
}

正如文档所说,该属性的作用是:

控制接收器是否调整其边界的高度 当其文本视图调整大小时。默认值: NO。

If leave it with the default value, after resize the frame of someTextView, the size of the textContainer is not changed, leading to the result that the text can only be displayed in the area before resizing.

And maybe it is needed to set the scrollEnabled = NO in case there's more than one textContainer, so that the text will reflow from one textContainer to the another.

这里还有一个针对 简单和快速的原型设计的解决方案:

设置:

  1. 具有原型单元的表。
  2. 每个单元格包含动态大小的 UITextVieww/other 内容。
  3. 原型细胞与 TableCell.h相关联。
  4. UITableViewTableViewController.h相关联。

解决方案:

(1) Add to TableViewController.m:

 // This is the method that determines the height of each cell.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// I am using a helper method here to get the text at a given cell.
NSString *text = [self getTextAtIndex:indexPath];


// Getting the height needed by the dynamic text view.
CGSize size = [self frameForText:text sizeWithFont:nil constrainedToSize:CGSizeMake(300.f, CGFLOAT_MAX)];


// Return the size of the current row.
// 80 is the minimum height! Update accordingly - or else, cells are going to be too thin.
return size.height + 80;
}


// Think of this as some utility function that given text, calculates how much
// space would be needed to fit that text.
- (CGSize)frameForText:(NSString *)text sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
{
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
nil];
CGRect frame = [text boundingRectWithSize:size
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:attributesDictionary
context:nil];


// This contains both height and width, but we really care about height.
return frame.size;
}


// Think of this as a source for the text to be rendered in the text view.
// I used a dictionary to map indexPath to some dynamically fetched text.
- (NSString *) getTextAtIndex: (NSIndexPath *) indexPath
{
return @"This is stubbed text - update it to return the text of the text view.";
}

(2)在 TableCell.m加入:

// This method will be called when the cell is initialized from the storyboard
// prototype.
- (void)awakeFromNib
{
// Assuming TextView here is the text view in the cell.
TextView.scrollEnabled = YES;
}

Explanation:

所以这里发生的是: 每个文本视图通过垂直和水平约束绑定到表单元格的高度-这意味着当表单元格高度增加时,文本视图也会增加其大小。我使用@manecosta 代码的修改版本来计算文本视图所需的高度,以适应单元格中给定的文本。因此,这意味着给定一个具有 X 个字符的文本,frameForText:将返回一个大小,该大小将具有与文本视图所需高度匹配的属性 size.height

现在,剩下的就是更新单元格的高度以匹配所需的文本视图的高度。这是在 heightForRowAtIndexPath:实现的。正如注释中指出的,由于 size.height只是文本视图的高度,而不是整个单元格的高度,因此应该向它添加一些偏移量。在本例中,该值为80。

如果你正在使用 UITableViewAutomatic維度,我有一个非常简单的(只有 iOS8)解决方案。在我的例子中,它是一个静态表视图,但我想您可以将其用于动态原型..。

我为文本视图的高度设置了一个约束出口,并实现了以下方法:

// Outlets


@property (weak, nonatomic) IBOutlet UITextView *textView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewHeight;




// Implementation


#pragma mark - Private Methods


- (void)updateTextViewHeight {
self.textViewHeight.constant = self.textView.contentSize.height + self.textView.contentInset.top + self.textView.contentInset.bottom;
}


#pragma mark - View Controller Overrides


- (void)viewDidLoad {
[super viewDidLoad];
[self updateTextViewHeight];
}


#pragma mark - TableView Delegate & Datasource


- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80;
}


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}


#pragma mark - TextViewDelegate


- (void)textViewDidChange:(UITextView *)textView {
[self.tableView beginUpdates];
[self updateTextViewHeight];
[self.tableView endUpdates];
}

但是请记住 : 文本视图必须是可滚动的,并且您必须设置您的约束,使其适用于自动维度:

  • 设置单元格中相互关联的所有视图,具有固定的高度(包括文本视图高度,您将以编程方式更改该高度)
  • 顶部多数视图具有顶部间距,底部多数视图具有底部间距;

最基本的单元格例子是:

  • 除了文本视图,单元格中没有其他视图
  • 文本视图的所有边距为0,并为文本视图预定义了高度约束。

快速版

func textViewHeightForAttributedText(text: NSAttributedString, andWidth width: CGFloat) -> CGFloat {
let calculationView = UITextView()
calculationView.attributedText = text
let size = calculationView.sizeThatFits(CGSize(width: width, height: CGFloat.max))
return size.height
}

完全平滑解如下。

First, we need the cell class with a textView

@protocol TextInputTableViewCellDelegate <NSObject>
@optional
- (void)textInputTableViewCellTextWillChange:(TextInputTableViewCell *)cell;
- (void)textInputTableViewCellTextDidChange:(TextInputTableViewCell *)cell;
@end


@interface TextInputTableViewCell : UITableViewCell
@property (nonatomic, weak) id<TextInputTableViewCellDelegate> delegate;
@property (nonatomic, readonly) UITextView *textView;
@property (nonatomic) NSInteger minLines;
@property (nonatomic) CGFloat lastRelativeFrameOriginY;
@end




#import "TextInputTableViewCell.h"


@interface TextInputTableViewCell () <UITextViewDelegate> {
NSLayoutConstraint *_heightConstraint;
}
@property (nonatomic) UITextView *textView;
@end


@implementation TextInputTableViewCell


- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.selectionStyle = UITableViewCellSelectionStyleNone;


_textView = [UITextView new];
_textView.translatesAutoresizingMaskIntoConstraints = NO;
_textView.delegate = self;
_textView.scrollEnabled = NO;
_textView.font = CELL_REG_FONT;
_textView.textContainer.lineFragmentPadding = 0.0;
_textView.textContainerInset = UIEdgeInsetsZero;
[self.contentView addSubview:_textView];


[self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];
[self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];


_heightConstraint = [NSLayoutConstraint constraintWithItem: _textView
attribute: NSLayoutAttributeHeight
relatedBy: NSLayoutRelationGreaterThanOrEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 0.0
constant: (_textView.font.lineHeight + 15)];
_heightConstraint.priority = UILayoutPriorityRequired - 1;
[_textView addConstraint:_heightConstraint];
}
return self;
}


- (void)prepareForReuse {
[super prepareForReuse];
self.minLines = 1;
}


- (void)setMinLines:(NSInteger)minLines {
_heightConstraint.constant = minLines * _textView.font.lineHeight + 15;
}


- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ([self.delegate respondsToSelector:@selector(textInputTableViewCellTextWillChange:)]) {
[self.delegate textInputTableViewCellTextWillChange:self];
}
return YES;
}


- (void)textViewDidChange:(UITextView *)textView {
if ([self.delegate respondsToSelector:@selector(textInputTableViewCellTextDidChange:)]) {
[self.delegate textInputTableViewCellTextDidChange:self];
}
}

接下来,我们在 TableViewController 中使用它

@interface SomeTableViewController () <TextInputTableViewCellDelegate>
@end


@implementation SomeTableViewController


. . . . . . . . . . . . . . . . . . . .


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {


TextInputTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: TextInputTableViewCellIdentifier forIndexPath:indexPath];
cell.delegate = self;
cell.minLines = 3;
. . . . . . . . . .
return cell;
}


- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}


- (void)textInputTableViewCellWillChange:(TextInputTableViewCell *)cell {
cell.lastRelativeFrameOriginY = cell.frame.origin.y - self.tableView.contentOffset.y;
}


- (void)textInputTableViewCellTextDidChange:(TextInputTableViewCell *)cell {
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];


[UIView performWithoutAnimation:^{
[self.tableView moveRowAtIndexPath:indexPath toIndexPath:indexPath];
}];


CGFloat contentOffsetY = cell.frame.origin.y - cell.lastRelativeFrameOriginY;
self.tableView.contentOffset = CGPointMake(self.tableView.contentOffset.x, contentOffsetY);


CGRect caretRect = [cell.textView caretRectForPosition:cell.textView.selectedTextRange.start];
caretRect = [self.tableView convertRect:caretRect fromView:cell.textView];


CGRect visibleRect = self.tableView.bounds;
visibleRect.origin.y += self.tableView.contentInset.top;
visibleRect.size.height -= self.tableView.contentInset.top + self.tableView.contentInset.bottom;
BOOL res = CGRectContainsRect(visibleRect, caretRect);
if (!res) {
caretRect.size.height += 5;
[self.tableView scrollRectToVisible:caretRect animated:NO];
}
}
@end
  • 这里 minLines允许设置 textView 的最小高度(到 抵抗高度最小化自动布局

  • 具有相同索引路径的 moveRowAtIndexPath:indexPath: tableViewCell height re-calculation and re-layout.

  • performWithoutAnimation:消除了副作用(tableView 内容) 在输入时开始新行时的偏移跳转)

  • 重要的是保存 relativeFrameOriginY(不 在单元格更新期间使用 contentOffsetY!) ,因为 可以通过自动布局演算更改当前单元格之前的单元格 它消除了系统连接的视觉跳跃 一边打着长长的单词

  • 注意,不应该设置属性 estimatedRowHeight! < em > The 跟踪不起作用

    self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;
    

    Use only tableViewDelegate method.

==========================================================================

如果不介意 TableViewtableViewCell之间的弱绑定和从 tableViewCell更新 tableView 的几何图形,那么可以升级以上的 TextInputTableViewCell类:

@interface TextInputTableViewCell : UITableViewCell
@property (nonatomic, weak) id<TextInputTableViewCellDelegate> delegate;
@property (nonatomic, weak) UITableView *tableView;
@property (nonatomic, readonly) UITextView *textView;
@property (nonatomic) NSInteger minLines;
@end




#import "TextInputTableViewCell.h"


@interface TextInputTableViewCell () <UITextViewDelegate> {
NSLayoutConstraint *_heightConstraint;
CGFloat _lastRelativeFrameOriginY;
}
@property (nonatomic) UITextView *textView;
@end


@implementation TextInputTableViewCell


- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.selectionStyle = UITableViewCellSelectionStyleNone;


_textView = [UITextView new];
_textView.translatesAutoresizingMaskIntoConstraints = NO;
_textView.delegate = self;
_textView.scrollEnabled = NO;
_textView.font = CELL_REG_FONT;
_textView.textContainer.lineFragmentPadding = 0.0;
_textView.textContainerInset = UIEdgeInsetsZero;
[self.contentView addSubview:_textView];


[self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];
[self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];


_heightConstraint = [NSLayoutConstraint constraintWithItem: _textView
attribute: NSLayoutAttributeHeight
relatedBy: NSLayoutRelationGreaterThanOrEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 0.0
constant: (_textView.font.lineHeight + 15)];
_heightConstraint.priority = UILayoutPriorityRequired - 1;
[_textView addConstraint:_heightConstraint];
}
return self;
}


- (void)prepareForReuse {
[super prepareForReuse];
self.minLines = 1;
self.tableView = nil;
}


- (void)setMinLines:(NSInteger)minLines {
_heightConstraint.constant = minLines * _textView.font.lineHeight + 15;
}


- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {


_lastRelativeFrameOriginY = self.frame.origin.y - self.tableView.contentOffset.y;
return YES;
}


- (void)textViewDidChange:(UITextView *)textView {


NSIndexPath *indexPath = [self.tableView indexPathForCell:self];
if (indexPath == nil) return;


[UIView performWithoutAnimation:^{
[self.tableView moveRowAtIndexPath:indexPath toIndexPath:indexPath];
}];


CGFloat contentOffsetY = self.frame.origin.y - _lastRelativeFrameOriginY;
self.tableView.contentOffset = CGPointMake(self.tableView.contentOffset.x, contentOffsetY);


CGRect caretRect = [self.textView caretRectForPosition:self.textView.selectedTextRange.start];
caretRect = [self.tableView convertRect:caretRect fromView:self.textView];


CGRect visibleRect = self.tableView.bounds;
visibleRect.origin.y += self.tableView.contentInset.top;
visibleRect.size.height -= self.tableView.contentInset.top + self.tableView.contentInset.bottom;


BOOL res = CGRectContainsRect(visibleRect, caretRect);
if (!res) {
caretRect.size.height += 5;
[self.tableView scrollRectToVisible:caretRect animated:NO];
}
}
@end

For iOS 8 and above you can just use

你想要的 your_tablview.estimatedrowheight= minheight

your_tableview.rowheight=UItableviewautomaticDimension

如果要根据内部 UITextView的高度自动调整 UITableViewCell的高度。在这里可以看到我的答案: https://stackoverflow.com/a/45890087/1245231

这个解决方案非常简单,从 iOS7开始就可以使用。确保在 StoryBoard 中的 UITableViewCell中的 UITextViewScrolling Enabled选项被转换为 关掉

然后在 UITableViewController 的 viewDidLoad ()中设置 tableView.rowHeight = UITableViewAutomaticDimensiontableView.estimatedRowHeight > 0,例如:

override func viewDidLoad() {
super.viewDidLoad()


tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44.0
}

就是这样。 UITableViewCell的高度将根据内部 UITextView的高度自动调整。

  1. 将 UILabel 置于 UITextView 之后。
  2. 使用这个答案: https://stackoverflow.com/a/36054679/6681462到您创建的 UILabel
  3. 给它们相同的约束和字体
  4. Set them same text;

单元格的高度将由 UILabel 的内容计算,但所有文本将由 TextField 显示。