[cocoa-touch] iOS 7에서 UITextView 높이가있는 UITableViewCell?

iOS 7에서 UITextView가있는 UITableViewCell의 높이를 어떻게 계산할 수 있습니까?

비슷한 질문에 대한 많은 답변을 찾았지만 sizeWithFont:모든 솔루션에 참여하며이 방법은 더 이상 사용되지 않습니다!

사용해야한다는 것을 알고 - (CGFloat)tableView:heightForRowAtIndexPath:있지만 TextView가 전체 텍스트를 표시하는 데 필요한 높이를 어떻게 계산합니까?



답변

우선, 텍스트가 렌더링되는 방식과 관련하여 UITextView와 UILabel간에 큰 차이가 있다는 점에 유의하는 것이 매우 중요합니다. UITextView는 모든 테두리에 인세 트가있을뿐만 아니라 내부의 텍스트 레이아웃도 약간 다릅니다.

따라서, 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;
}

이 함수는 a NSAttributedString와 원하는 너비를 a로 취하고 CGFloat필요한 높이를 반환합니다.


세부 솔루션

최근에 비슷한 일을했기 때문에 제가 직면 한 연결된 문제에 대한 몇 가지 해결책을 공유 할 것이라고 생각했습니다. 누군가에게 도움이되기를 바랍니다.

이것은 훨씬 더 깊이 있고 다음을 다룰 것입니다.

  • 물론 : UITableViewCell포함 된 전체 내용을 표시하는 데 필요한 크기에 따라 의 높이를 설정합니다.UITextView
  • 텍스트 변경에 응답 (및 행의 높이 변경에 애니메이션 적용)
  • 편집 UITextView하는 UITableViewCell동안 크기를 조정할 때 커서를 보이는 영역 안에두고 첫 번째 응답자를 유지

정적 테이블 뷰로 작업하거나 알려진 수의 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는 사전에 유효한 키입니다 )

- (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은 내부 jQuery과의 보이는 사각형이 아닌 경우, 커서의 위치로 스크롤 :

- (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 삽입이 조정되지 않으면 tableview scrollToCursorForTextView:의 맨 아래에있는 경우 커서로 스크롤 할 수 없습니다.

- (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찾을 수없는 문제가있는 경우 기능의 업데이트 된 버전을 확인하십시오.


답변

boundingRectWithSize 인 sizeWithFont를 대체하는 새로운 함수가 있습니다.

내 프로젝트에 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 )


답변

UITableViewAutomaticDimension을 사용하는 경우 정말 간단한 (iOS 8 전용) 솔루션이 있습니다. 제 경우에는 정적 테이블 뷰이지만 동적 프로토 타입에 맞게 조정할 수 있다고 생각합니다.

텍스트 뷰의 높이에 대한 제한 콘센트가 있고 다음과 같은 방법을 구현했습니다.

// 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];
}

그러나 기억하세요 : 텍스트보기는 스크롤 가능해야하며 자동 치수에 대해 작동하도록 제약 조건을 설정해야합니다.

  • 고정 높이 (프로그래밍 방식으로 변경할 텍스트보기 높이 포함)를 사용하여 서로 관련하여 셀의 모든보기를 설정합니다.
  • 맨 위보기에는 맨 위 간격이 있고 맨 아래보기에는 수퍼 뷰에 대한 맨 아래 간격이 있습니다.

가장 기본적인 셀 예는 다음과 같습니다.

  • textview를 제외하고 셀에 다른보기가 없습니다.
  • 텍스트보기의 모든면 주위에 여백이 0이고 텍스트보기에 대해 미리 정의 된 높이 제한이 있습니다.

답변

Tim Bodeit의 대답은 훌륭합니다. Simple Solution의 코드를 사용하여 텍스트 뷰의 높이를 올바르게 가져오고 해당 높이를 heightForRowAtIndexPath. 하지만 나머지 답변을 사용하여 텍스트보기의 크기를 조정하지 않습니다. 대신에서 frame텍스트보기 를 변경하는 코드를 작성합니다 cellForRowAtIndexPath.

모든 것이 iOS 6 이하에서 작동하지만 iOS 7에서는 frame텍스트보기의 크기가 실제로 조정 되어도 텍스트보기의 텍스트를 완전히 표시 할 수 없습니다 . (나는 사용하지 않습니다 Auto Layout). 아이폰 OS 7가 있다는 이유해야 TextKit하고 텍스트의 위치에 의해 제어됩니다 NSTextContainer에서 UITextView. 따라서 제 경우 someTextView에는 iOS 7에서 올바르게 작동 하도록 설정하는 줄을 추가해야합니다 .

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

문서에서 말했듯이 해당 속성의 기능은 다음과 같습니다.

수신자가 텍스트보기의 크기를 조정할 때 경계 사각형의 높이를 조정할지 여부를 제어합니다. 기본값 : 아니오.

기본값으로두면, 후 크기를 조정 framesomeTextView,의 크기를textContainer 텍스트 만 크기를 조정하기 전에 영역에 표시 할 수 있습니다, 그 결과로 이어지는 변경되지 않습니다.

그리고 텍스트가 하나 에서 다른 것으로 리플 로우되도록 scrollEnabled = NO둘 이상의 를 설정해야 할 수도 있습니다 .textContainertextContainer


답변

단순성과 빠른 프로토 타이핑 을 목표로하는 또 하나의 솔루션이 있습니다 .

설정:

  1. 프로토 타입 셀이있는 테이블.
  2. 각 셀에는 동적 크기가 포함됩니다. UITextView 다른 내용과 함께 됩니다.
  3. 프로토 타입 셀은 TableCell.h.
  4. UITableView와 연결되어 TableViewController.h있습니다.

해결책:

(1) 추가 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;
}

설명:

그래서 여기서 일어나는 것은 이것이다 : 각 텍스트 뷰는 수직 및 수평 제약에 의해 테이블 ​​셀의 높이에 바인딩됩니다. 즉, 테이블 셀 높이가 증가하면 텍스트 뷰도 크기가 증가합니다. @manecosta 코드의 수정 된 버전을 사용하여 주어진 텍스트를 셀에 맞추기 위해 필요한 텍스트보기 높이를 계산했습니다. 즉, X 개의 문자가있는 텍스트가 주어진 frameForText:경우 속성이있는 크기를 반환합니다.size.height 텍스트보기의 필수 높이와 일치 을 .

이제 남은 것은 필요한 텍스트 뷰의 높이와 일치하도록 셀의 높이를 업데이트하는 것입니다. 그리고 이것은 heightForRowAtIndexPath:. 주석에서 언급했듯이 size.height전체 셀이 아니라 텍스트 뷰의 높이 일 뿐이므로 일부 오프셋이 추가되어야합니다. 예제의 경우이 값은 80입니다.


답변

자동 레이아웃을 사용하는 경우 한 가지 방법은 자동 레이아웃 엔진이 크기를 계산하도록하는 것입니다. 이것은 가장 효율적인 접근 방식은 아니지만 매우 편리합니다 (그리고 틀림없이 가장 정확합니다). 셀 레이아웃이 복잡 해짐에 따라 더 편리해집니다. 예를 들어 갑자기 셀에 둘 이상의 텍스트보기 / 필드가 있습니다.

자동 레이아웃을 사용하여 tableview 셀 크기를 조정하는 완전한 샘플로 비슷한 질문에 답했습니다.

자동 레이아웃을 사용하여 모든 하위보기에 맞게 superview의 크기를 조정하는 방법은 무엇입니까?


답변

완전한 부드러운 솔루션은 다음과 같습니다.

먼저 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의 최소 높이를 설정할 수 있습니다 (UITableViewAutomaticDimension을 사용하여 AutoLayout에 의해 최소화되는 높이에 저항하기 위해).

  • moveRowAtIndexPath:indexPath: 동일한 indexPath를 사용하면 tableViewCell 높이 재 계산 및 레이아웃이 시작됩니다.

  • performWithoutAnimation: 부작용을 제거합니다 (입력하는 동안 새 줄 시작에서 점프하는 tableView 콘텐츠 오프셋).

  • 현재 셀이 예상치 못한 방식으로 autoLayout 미적분에 의해 변경 될 수 있기 전에 셀 업데이트 중에 보존 relativeFrameOriginY(
    contentOffsetY! 아님)하는 것이 중요합니다 contentSize. 긴 단어를 입력하는 동안 시스템 하이픈 연결시 시각적 점프를 제거합니다.

  • 속성을 설정하지 마십시오 estimatedRowHeight ! 다음은 작동하지 않습니다.

    self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;

    tableViewDelegate 메소드 만 사용하십시오.

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

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