¿UITableViewCell con altura de UITextView en iOS 7?

¿Cómo puedo calcular la altura de una UITableViewCell con una UITextView en iOS 7?

Encontré muchas respuestas a preguntas similares, pero sizeWithFont: toma parte en todas las soluciones y este método está en desuso!

Sé que tengo que usar - (CGFloat)tableView:heightForRowAtIndexPath: pero ¿cómo puedo calcular la altura que mi TextView necesita para mostrar todo el texto?

En primer lugar, es muy importante tener en cuenta que existe una gran diferencia entre UITextView y UILabel cuando se trata de cómo se procesa el texto. No solo UITextView tiene inserciones en todas las fronteras, sino que también el diseño de texto que contiene es ligeramente diferente.

Por lo tanto, sizeWithFont: es un mal camino para UITextViews.

En cambio, UITextView tiene una función llamada sizeThatFits: que devolverá el tamaño más pequeño necesario para mostrar todos los contenidos de UITextView dentro de un cuadro delimitador, que puede especificar.

Lo siguiente funcionará igualmente para iOS 7 y versiones anteriores y, a partir de ahora, no incluye ningún método que esté en desuso.


Solución simple

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

Esta función tomará un NSAttributedString y el ancho deseado como un CGFloat y devolverá la altura necesaria


Solución detallada

Como hace poco hice algo similar, pensé que también compartiría algunas soluciones para los Problemas conectados que encontré. Espero que ayude a alguien.

Esto es mucho más profundo y cubrirá lo siguiente:

  • Por supuesto: establecer la altura de una UITableViewCell función del tamaño necesario para mostrar el contenido completo de una UITextView contenida
  • Responder a los cambios de texto (y animar los cambios de altura de la fila)
  • Mantener el cursor dentro del área visible y mantener la primera respuesta en UITextView al cambiar el tamaño de UITableViewCell mientras se edita

Si está trabajando con una vista de tabla estática o si solo tiene una cantidad conocida de UITextView , puede hacer que el paso 2 sea mucho más simple.

1. Primero, sobrescriba 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. Defina la función que calculó la altura necesaria:

Agregue un NSMutableDictionary (en este ejemplo, llamado textViews ) como una variable de instancia a su subclase UITableViewController .

Utilice este diccionario para almacenar referencias a las UITextViews individuales de UITextViews manera:

(y sí, indexPaths son claves válidas para diccionarios )

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

Esta función ahora calculará la altura real:

 - (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. Habilite el cambio de tamaño durante la edición

Para las siguientes dos funciones, es importante que el delegado de UITextViews esté configurado en UITableViewController . Si necesita algo más como delegado, puede solucionarlo haciendo las llamadas pertinentes desde allí o utilizando los ganchos de NSNotificationCenter apropiados.

 - (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 (eg through autolayout // constraints), resize it here [self scrollToCursorForTextView:textView]; // OPTIONAL: Follow cursor } 

4. Siga el cursor mientras edita

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

Esto hará que UITableView desplace hasta la posición del cursor, si no está dentro del Rect visible de 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. Ajuste el rect visible, estableciendo inserciones

Durante la edición, partes de su UITableView pueden ser cubiertas por el teclado. Si las inserciones de las tablas no están ajustadas, scrollToCursorForTextView: no podrá desplazarse hacia su cursor, si está en la parte inferior de la tabla.

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

Y la última parte:

Dentro de su vista se cargó, regístrese para las Notificaciones de cambios en el teclado a través de 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]; } 

Por favor, no te enojes conmigo por hacer que esta respuesta sea tan larga. Si bien no se necesita todo para responder la pregunta, creo que hay otras personas a quienes estos temas directamente relacionados serán útiles.


ACTUALIZAR:

Como Dave Haupert señaló, olvidé incluir la función 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); } 

También noté que scrollToCursorForTextView: todavía incluía una referencia directa a uno de los campos de texto en mi proyecto. Si tiene un problema con bodyTextView no se encuentra, verifique la versión actualizada de la función.

Hay una nueva función para reemplazar sizeWithFont, que es boundingRectWithSize.

Agregué la siguiente función a mi proyecto, que hace uso de la nueva función en iOS7 y la anterior en iOS menor que 7. Tiene básicamente la misma syntax que 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 } } 

Puede agregar ese IOS_NEWER_OR_EQUAL_TO_7 en su archivo prefix.pch en su proyecto como:

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

Si está utilizando UITableViewAutomaticDimension tengo una solución realmente simple (iOS 8 solamente). En mi caso, es una vista de tabla estática, pero supongo que podrías adaptar esto para prototipos dynamics …

Tengo una salida de restricción para la altura de la vista de texto y he implementado los siguientes métodos como este:

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

Pero recuerde : la vista de texto debe ser desplazable, y debe configurar sus restricciones de modo que funcionen para la dimensión automática:

  • configura toda la vista en la celda en relación entre sí, con alturas fijas (incluida la altura de la vista de texto, que cambiarás programáticamente)
  • la vista superior tiene el espaciado superior y la vista inferior tiene el espaciado inferior a la vista superior;

El ejemplo de celda más básico es:

  • no hay otras vistas en la celda, excepto la vista de texto
  • 0 márgenes alrededor de todos los lados de la vista de texto y una restricción de altura predefinida para la vista de texto.

La respuesta de Tim Bodeit es genial. heightForRowAtIndexPath el código de Simple Solution para obtener correctamente el alto de la vista de texto, y uso esa altura en heightForRowAtIndexPath . Pero no uso el rest de la respuesta para cambiar el tamaño de la vista de texto. En cambio, escribo código para cambiar el frame de la vista de texto en cellForRowAtIndexPath .

Todo está funcionando en iOS 6 y versiones posteriores, pero en iOS 7, el texto en la vista de texto no se puede mostrar completamente aunque el frame de la vista de texto sí se haya cambiado de tamaño. (No estoy usando Auto Layout ). Debería ser la razón por la que en iOS 7 hay TextKit y la posición del texto está controlada por NSTextContainer en UITextView . Entonces, en mi caso, necesito agregar una línea para configurar el someTextView para que funcione correctamente en iOS 7.

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

Como decía la documentación, lo que hace esa propiedad es:

Controla si el receptor ajusta la altura de su rectángulo delimitador cuando se cambia el tamaño de su vista de texto. Valor predeterminado: NO.

Si lo deja con el valor predeterminado, después de cambiar el tamaño del frame de someTextView , el tamaño del textContainer no cambia, lo que lleva al resultado de que el texto solo se puede mostrar en el área antes de cambiar el tamaño.

Y tal vez sea necesario configurar el scrollEnabled = NO en caso de que haya más de un textContainer , de modo que el texto textContainer a textContainer un textContainer a otro.

Aquí hay una solución más que apunta a la simplicidad y la creación rápida de prototipos :

Preparar:

  1. Tabla con células prototipo.
  2. Cada celda contiene UITextView tamaño dynamic con otros contenidos.
  3. Las células de prototipo están asociadas con TableCell.h .
  4. UITableView está asociado con TableViewController.h .

Solución:

(1) Agregar a 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) Agregar a 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; } 

Explicación:

Entonces, lo que está sucediendo aquí es esto: cada vista de texto está ligada al alto de las celdas de la tabla por restricciones verticales y horizontales, eso significa que cuando la altura de la celda de la tabla aumenta, la vista de texto también aumenta su tamaño. Utilicé una versión modificada del código de @ manecosta para calcular la altura requerida de una vista de texto para que se ajuste al texto dado en una celda. Entonces eso significa que, dado un texto con un número de caracteres X, frameForText: devolverá un tamaño que tendrá una propiedad size.height que coincida con la altura requerida de la vista de texto.

Ahora, todo lo que queda es actualizar la altura de la celda para que coincida con la altura de la vista de texto requerida. Y esto se logra en heightForRowAtIndexPath: Como se señaló en los comentarios, dado que size.height es solo la altura de la vista de texto y no la celda completa, debe haber algún desplazamiento agregado. En el caso del ejemplo, este valor fue 80.

Un enfoque si está utilizando el diseño automático es dejar que el motor de diseño automático calcule el tamaño para usted. Este no es el enfoque más eficiente, pero es bastante conveniente (y podría decirse que es el más preciso). Se vuelve más conveniente a medida que crece la complejidad del diseño de la celda, por ejemplo, repentinamente tiene dos o más textviews / campos en la celda.

Respondí una pregunta similar con una muestra completa para dimensionar las celdas de la tabla usando el diseño automático, aquí:

¿Cómo cambiar el tamaño de la supervista para que se ajuste a todas las subvistas con autolayout?

La solución completa y sin problemas es la siguiente.

Primero, necesitamos la clase celular con un textView

 @protocol TextInputTableViewCellDelegate  @optional - (void)textInputTableViewCellTextWillChange:(TextInputTableViewCell *)cell; - (void)textInputTableViewCellTextDidChange:(TextInputTableViewCell *)cell; @end @interface TextInputTableViewCell : UITableViewCell @property (nonatomic, weak) id delegate; @property (nonatomic, readonly) UITextView *textView; @property (nonatomic) NSInteger minLines; @property (nonatomic) CGFloat lastRelativeFrameOriginY; @end #import "TextInputTableViewCell.h" @interface TextInputTableViewCell ()  { 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]; } } 

A continuación, lo usamos en TableViewController

 @interface SomeTableViewController ()  @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 
  • Aquí minLines permite establecer la altura mínima para textView (para resistir la minimización de altura mediante AutoLayout con UITableViewAutomaticDimension).

  • moveRowAtIndexPath:indexPath: con el mismo indexPath se inicia el recálculo y el rediseño de la altura de tableViewCell.

  • performWithoutAnimation: elimina los efectos secundarios (offset de contenido tableView salta al iniciar una nueva línea mientras se escribe).

  • Es importante preservar relativeFrameOriginY (¡no contentOffsetY !) Durante la actualización de celda porque el contentSize de contentSize de las celdas antes de la celda actual podría cambiarse por autoLayout calculus de forma inesperada. Elimina los saltos visuales en la separación por sílabas del sistema al escribir palabras largas.

  • Tenga en cuenta que no debe establecer la propiedad estimatedRowHeight ! Lo siguiente no funciona

     self.tableView.estimatedRowHeight = UITableViewAutomaticDimension; 

    Use solo el método tableViewDelegate.

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

Si a uno no le molesta la unión débil entre tableView y tableViewCell y la actualización de la geometría de tableView desde tableViewCell , es posible actualizar la clase TextInputTableViewCell arriba:

 @interface TextInputTableViewCell : UITableViewCell @property (nonatomic, weak) id delegate; @property (nonatomic, weak) UITableView *tableView; @property (nonatomic, readonly) UITextView *textView; @property (nonatomic) NSInteger minLines; @end #import "TextInputTableViewCell.h" @interface TextInputTableViewCell ()  { 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 
  1. Ponga UILabel detrás de su UITextView.
  2. Usa esta respuesta: https://stackoverflow.com/a/36054679/6681462 para UILabel que has creado
  3. Deles las mismas restricciones y fonts
  4. Establecerlos el mismo texto;

La altura de su celda se calculará según el contenido de UILabel, pero TextField mostrará todo el texto.

 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; 

Creo que de esta manera puedes contar el alto de tu vista de texto y luego redimensionar tu celda de tabla de acuerdo con esa altura para que puedas mostrar el texto completo en la celda

Versión Swift

 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 } 

Si desea ajustar automáticamente la altura de UITextView en función de la altura de la altura interna de UITextView . Ver mi respuesta aquí: https://stackoverflow.com/a/45890087/1245231

La solución es bastante simple y debería funcionar desde iOS 7. Asegúrese de que la opción Scrolling Enabled esté desactivada para UITextView dentro de UITableViewCell en StoryBoard.

Luego, en el viewDidLoad () de UITableViewController configure tableView.rowHeight = UITableViewAutomaticDimension y tableView.estimatedRowHeight > 0 , como:

 override func viewDidLoad() { super.viewDidLoad() tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = 44.0 } 

Eso es. La altura de UITableViewCell se ajustará automáticamente en función de la UITextView interna de UITextView .

Para iOS 8 y superior, solo puede usar

your_tablview.estimatedrowheight= minheight que quieras

 your_tableview.rowheight=UItableviewautomaticDimension