¿UITableViewCell con altura UITextView en iOS 7?

121

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

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

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

MyJBMe
fuente

Respuestas:

428

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 representa el texto. UITextView no solo tiene inserciones en todos los bordes, sino que también el diseño del texto es ligeramente diferente.

Por lo tanto, sizeWithFont:es una mala manera de ir a UITextViews.

En UITextViewsu lugar , tiene una función llamada sizeThatFits:que devolverá el tamaño más pequeño necesario para mostrar todos los contenidos del UITextViewinterior 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á NSAttributedStringay el ancho deseado como a CGFloaty devolverá la altura necesaria


Solución detallada

Como recientemente hice algo similar, pensé que también compartiría algunas soluciones a 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 un en UITableViewCellfunción del tamaño necesario para mostrar el contenido completo de un contenidoUITextView
  • Responda a los cambios de texto (y anime los cambios de altura de la fila)
  • Mantener el cursor dentro del área visible y mantener el primer respondedor UITextViewal cambiar el tamaño UITableViewCellmientras se edita

Si está trabajando con una vista de tabla estática o solo tiene un número conocido de UITextViews, puede hacer que el paso 2 sea mucho más simple.

1. Primero, sobrescriba la 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 UITableViewControllersubclase.

Use este diccionario para almacenar referencias al individuo de la siguiente UITextViewsmanera:

(y sí, indexPaths son claves válidas para los 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 mientras edita

Para las siguientes dos funciones, es importante que el delegado de la UITextViewsse establezca en su UITableViewController. Si necesita algo más como delegado, puede solucionarlo haciendo las llamadas relevantes desde allí o utilizando los enlaces apropiados de 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. Siga el cursor mientras edita

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

Esto hará que el UITableViewdesplazamiento a 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ángulo visible, colocando insertos

Durante la edición, partes del suyo UITableViewpueden estar cubiertas por el teclado. Si las inserciones de las vistas de tabla no están ajustadas, scrollToCursorForTextView:no podrá desplazarse hasta el cursor, si está en la parte inferior de la vista de 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 última parte:

Dentro de su vista se cargó, regístrese para las notificaciones de cambios de 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 esta respuesta tanto tiempo. Si bien no todo es necesario para responder la pregunta, creo que hay otras personas a quienes estos temas directamente relacionados serán útiles.


ACTUALIZAR:

Como señaló Dave Haupert, olvidé incluir la rectVisiblefunción:

- (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 TextFields en mi proyecto. Si tiene un problema con bodyTextViewno ser encontrado, verifique la versión actualizada de la función.

Tim Bodeit
fuente
1
¡Ese código está funcionando bien! ¡Cambia el tamaño de todo! ¡Pero mi TextView siempre tiene una altura de 30px! ¿Hay configuraciones que no tengo permitido establecer, o hay algo que no tengo permitido en UITextView?
MyJBMe
1
Esta solución no parece funcionar en copiar y pegar si el texto es grande, ¿alguna idea?
vikingos
2
@Tim Bodeit, su solución funciona, ¡gracias! Pero creo que debe tener en cuenta en el comentario, que la asignación de attributedTextsin especificar la fuente, el color y la alineación del texto conduce a la configuración de los valores predeterminados de los atributos NSAttributedString para textView. En mi caso, causa obtener diferentes alturas de la vista de texto para el mismo texto.
Alexander
44
Esta es una de mis respuestas favoritas de Stack Overflow, ¡gracias!
Richard Venable
3
@TimBodeit: No puedo hacer que esto funcione en iOS8. Por favor, hágame saber cómo se puede solucionar esto.
Arun Gupta
37

Hay una nueva función para reemplazar sizeWithFont, que está delimitandoRectWithSize.

Agregué la siguiente función a mi proyecto, que hace uso de la nueva función en iOS7 y la anterior en iOS inferior a 7. Tiene básicamente la misma sintaxis 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 )
manecosta
fuente
Mis UITextViews todavía no se escalan muy bien y se vuelven desplazables cuando el texto abarca 3 líneas; pastebin.com/Wh6vmBqh
Martin de Keijzer
La segunda declaración de devolución también arroja una advertencia de desuso en XCode.
Martin de Keijzer
¿También está configurando el tamaño de UItextView al tamaño calculado del texto, en cellForRowAtIndexPath? Además, no debe preocuparse por la advertencia en la segunda devolución, ya que solo se usa cuando la aplicación se ejecuta en un dispositivo iOS6 en el que la función no está en desuso.
manecosta
¿Puede proporcionar un ejemplo simple de cómo usar esta función?
Zorayr
@manecosta La documentación de Apple dice que debe 'limitar' el resultado: en iOS 7 y versiones posteriores, este método devuelve tamaños fraccionarios (en el componente de tamaño del CGRect devuelto); para usar un tamaño devuelto para vistas de tamaño, debe usar elevar su valor al entero más alto más cercano usando la función ceil.
HpTerm el
9

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

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:

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

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.
dec-vt100
fuente
1
la vista de texto NO debe ser desplazable
Akshit Zaveri
Estoy obteniendo el mismo tamaño en updateTextviewHeight todo el tiempo. Parece que el tamaño del contenido está mal. El desplazamiento está deshabilitado.
Dvole
5

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

Todo funciona en iOS 6 y versiones anteriores, pero en iOS 7 el texto en la vista de texto no se puede mostrar completamente aunque la framevista de texto se haya redimensionado. (No estoy usando Auto Layout). Debería ser la razón por la que en iOS 7 existe TextKity la posición del texto está controlada por NSTextContainerin UITextView. Entonces, en mi caso, necesito agregar una línea para configurarla someTextViewpara que funcione correctamente en iOS 7.

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

Como dice la documentación, lo que hace esa propiedad es:

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

Si lo deja con el valor predeterminado, después de cambiar el tamaño framede someTextView, el tamaño detextContainer 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 configurarlo scrollEnabled = NOen caso de que haya más de uno textContainer, para que el texto se refluya de uno textContainera otro.

PowerQian
fuente
4

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

Preparar:

  1. Mesa con células prototipo.
  2. Cada celda contiene tamaño dinámico UITextViewcon otros contenidos.
  3. Las células prototipo están asociadas con TableCell.h.
  4. UITableViewestá asociado con TableViewController.h.

Solución:

(1) Añadir 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á vinculada a la altura de las celdas de la tabla mediante 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. Usé una versión modificada del código de @ manecosta para calcular la altura requerida de una vista de texto para ajustar el texto dado en una celda. Eso significa que dado un texto con X número de caracteres, frameForText:devolverá un tamaño que tendrá una propiedad size.heightque 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 size.heightque solo es la altura de la vista de texto y no la celda completa, debería agregarse algún desplazamiento. En el caso del ejemplo, este valor fue 80.

Zorayr
fuente
¿Qué significa este 'dream.dream'?
MyJBMe
@MyJBMe, lo siento, fue parte de mi propio proyecto. He actualizado el código en consecuencia. dream.dreamera el texto que estaba renderizando en la vista de texto.
Zorayr
3

Un enfoque si está utilizando autolayout es dejar que el motor de autolayout calcule el tamaño por usted. Este no es el enfoque más eficiente, pero es bastante conveniente (y posiblemente el más preciso). Se vuelve más conveniente a medida que crece la complejidad del diseño de la celda, por ejemplo, de repente tiene dos o más vistas de texto / campos en la celda.

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

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

TomSwift
fuente
1

La solución suave completa es la siguiente.

Primero, necesitamos la clase de celda con 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];
    }
}

Luego, lo usamos en 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
  • Aquí minLinespermite establecer la altura mínima para textView (para resistir la minimización de altura mediante AutoLayout con UITableViewAutomaticDimension).

  • moveRowAtIndexPath:indexPath: con el mismo indexPath comienza el nuevo cálculo y el nuevo diseño de la altura de tableViewCell.

  • performWithoutAnimation: elimina el efecto secundario (salto de desplazamiento de contenido de vista de tabla al comenzar una nueva línea mientras se escribe).

  • Es importante preservar relativeFrameOriginY( contentOffsetY¡ no !) Durante la actualización contentSizede la celda debido a las celdas antes de que la celda actual pueda cambiarse por cálculo automático de forma inesperada. Elimina los saltos visuales en la separación silábica del sistema al escribir palabras largas.

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

    self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;

    Utilice solo el método tableViewDelegate.

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

Si a uno no le importa 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 TextInputTableViewCellclase anterior:

@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
malex
fuente
1
  1. Ponga UILabel detrás de su UITextView.
  2. Use esta respuesta: https://stackoverflow.com/a/36054679/6681462 a UILabel que creó
  3. Dales las mismas restricciones y fuentes
  4. Establecerles el mismo texto;

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

ilnur
fuente
0
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 puede contar la altura de su vista de texto y luego cambiar el tamaño de su celda de vista de tabla de acuerdo con esa altura para que pueda mostrar el texto completo en la celda

D-eptdeveloper
fuente
0

Versión rápida

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
}
Adam Smaka
fuente
0

Si desea ajustar automáticamente UITableViewCellla altura en función de la altura de la altura interior UITextView. Vea 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 Scrolling Enabledopción esté desactivada en el UITextViewinterior UITableViewCelldel StoryBoard.

Luego, en su UITableViewController viewDidLoad () establezca el tableView.rowHeight = UITableViewAutomaticDimensiony tableView.estimatedRowHeight > 0tales como:

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 44.0
}

Eso es. UITableViewCellLa altura se ajustará automáticamente en función de la UITextViewaltura interior .

petrsyn
fuente
-2

Para iOS 8 y superior solo puedes usar

your_tablview.estimatedrowheight= minheight usted quiere

your_tableview.rowheight=UItableviewautomaticDimension
Arenoso
fuente