2012-04-23 16 views
21

Tengo un UITableView que se rellena con celdas personalizadas (heredado de UITableViewCell), cada celda contiene un UIWebView que cambia de tamaño automáticamente en función de su contenido. Aquí está la cosa, ¿cómo puedo cambiar la altura de las celdas UITableView en función de su contenido (variable webView).Altura de la celda UITableView dinámica basada en el contenido

La solución debe ser dinámica, ya que el HTML utilizado para poblar el UIWebViews se analiza a partir de un feed siempre cambiante.

Tengo la sensación de que necesito utilizar el método delegado UITableViewheightForRowAtIndexPath pero a partir de su definición:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    ;//This needs to be variable 
} 

No puedo acceder a la célula o su contenido. ¿Puedo cambiar la altura de la celda en cellForRowAtIndexPath?

Cualquier ayuda sería grandiosa. Gracias.

Nota

Hice esta pregunta hace más de 2 años. Con la introducción del diseño automático la mejor solución para iOS7 se puede encontrar:

http://t.co/PdUywcTjhu

y en iOS8 esta funcionalidad está integrada en el SDK

Respuesta

17

La mejor manera que he encontrado para la altura dinámica es para calcular la altura de antemano y almacenarla en una colección de algún tipo (probablemente una matriz). Suponiendo que la celda contiene principalmente texto, puede usar -[NSString sizeWithFont:constrainedToSize:lineBreakMode:] para calcular la altura y luego devolver el valor correspondiente en heightForRowAtIndexPath:

[EDITAR ] Si el contenido es constantemente chan ging, podría implementar un método que actualizara el conjunto de alturas cuando se proporcionaran nuevos datos.

+0

gracias, buena solución, voy a trabajar en ello ahora –

+0

"sizeWithFont" obsoleta de iOS 7. En lugar utilizar "sizeWithAttributes". –

2

Aquí está el código que utilicé para la altura de celda dinámica al obtener tweets de Twitter y luego almacenarlos en CoreData para lectura fuera de línea.

Esto no sólo mostrará cómo obtener el contenido celular y datos, sino también la forma de dimensionar dinámicamente un UILabel al contenido con el acolchado

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 

    Tweet *tweet = [self.fetchedResultsController objectAtIndexPath:indexPath]; 

    NSString* text = tweet.Text; 

    TweetTableViewCell *cell = (TweetTableViewCell*)[self tableView:tableView cellForRowAtIndexPath:indexPath]; 

    //Set the maximum size 
    CGSize maximumLabelSize = cell.tweetLabel.frame.size; 
    CGPoint originalLocation = cell.tweetLabel.frame.origin; 

    //Calculate the new size based on the text 
    CGSize expectedLabelSize = [text sizeWithFont:cell.tweetLabel.font constrainedToSize:maximumLabelSize lineBreakMode:cell.tweetLabel.lineBreakMode]; 


    //Dynamically figure out the padding for the cell 
    CGFloat topPadding = cell.tweetLabel.frame.origin.y - cell.frame.origin.y; 


    CGFloat bottomOfLabel = cell.tweetLabel.frame.origin.y + cell.tweetLabel.frame.size.height; 
    CGFloat bottomPadding = cell.frame.size.height - bottomOfLabel; 


    CGFloat padding = topPadding + bottomPadding; 


    CGFloat topPaddingForImage = cell.profileImage.frame.origin.y - cell.frame.origin.y; 
    CGFloat minimumHeight = cell.profileImage.frame.size.height + topPaddingForImage + bottomPadding; 

    //adjust to the new size 
    cell.tweetLabel.frame = CGRectMake(originalLocation.x, originalLocation.y, cell.tweetLabel.frame.size.width, expectedLabelSize.height); 


    CGFloat cellHeight = expectedLabelSize.height + padding; 

    if (cellHeight < minimumHeight) { 

     cellHeight = minimumHeight; 
    } 

    return cellHeight; 
} 
+7

Llamar 'cellForRowAtIndexPath:' desde dentro de 'heightForRowAtIndexPath' no es una buena idea. Vea esta respuesta en su lugar: http://stackoverflow.com/a/5254852/969967 – Anthony

+1

Esta línea: TweetTableViewCell * cell = (TweetTableViewCell *) [self tableView: tableView cellForRowAtIndexPath: indexPath]; dequeues rehusable rows ... – Lucas

2

También pienso que tal algoritmo le conviene:

1) en cellForRowAtIndexPath que active su webviews para la carga y darles etiquetas iguales a indexPath.row

2) en webViewDidFinishLoading se calcula la altura del contenido de la celda, y componer un diccionario con claves y valores como esto: clave = indexPath.row valor = altura

3) llamar [tableview reloadData]

4) en [cellForRowAtIndexPath tableview: indexPath] ajustado alturas adecuadas para las células correspondientes

2

El gran problema con las células con La altura dinámica en iOS es que la tabla vc debe calcular y devolver una altura de cada celda antes de dibujar las celdas. Sin embargo, antes de dibujar una celda, no tiene un marco y, por lo tanto, no tiene ancho.Esto ocasiona un problema si su celda va a cambiar su altura según, por ejemplo, la cantidad de texto en el textoLabel, ya que no conoce su ancho.

Una solución común que he visto es que las personas definen un valor numérico para el ancho de la celda. Este es un mal enfoque, ya que las tablas pueden ser simples o agrupadas, usar iOS 7 o iOS 6, mostrarse en un iPhone o iPad, en modo horizontal o vertical, etc.

Luché con estos problemas en una aplicación de iOS mío, que admite iOS5 + y tanto iPhone como iPad con múltiples orientaciones. Necesitaba una forma conveniente de automatizar esto y dejar la lógica fuera del controlador de vista. El resultado se convirtió en una subclase UITableViewController (para que pueda contener el estado) que admite celdas predeterminadas (estilo predeterminado y de subtítulos), así como celdas personalizadas.

Puede agarrarlo en GitHub (https://github.com/danielsaidi/AutoSizeTableView). Espero que ayude a aquellos de ustedes que todavía luchan con este problema. Si lo compruebas, me encantaría saber lo que piensas y si te salió bien.

4

He intentado muchas soluciones, pero el que trabajaba era esto, sugerido por un amigo:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 

    int height = [StringUtils findHeightForText:yourLabel havingWidth:yourWidth andFont:[UIFont systemFontOfSize:17.0f]]; 

    height += [StringUtils findHeightForText:yourOtherLabel havingWidth:yourWidth andFont:[UIFont systemFontOfSize:14.0f]]; 

    return height + CELL_SIZE_WITHOUT_LABELS; //important to know the size of your custom cell without the height of the variable labels 
} 

La clase StringUtils.h:

#import <Foundation/Foundation.h> 

@interface StringUtils : NSObject 

+ (CGFloat)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font; 

@end 

clase StringUtils.m:

#import "StringUtils.h" 

@implementation StringUtils 

+ (CGFloat)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font { 
    CGFloat result = font.pointSize+4; 
    if (text) { 
     CGSize size; 

     CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) 
              options:NSStringDrawingUsesLineFragmentOrigin 
             attributes:@{NSFontAttributeName:font} 
              context:nil]; 
     size = CGSizeMake(frame.size.width, frame.size.height+1); 
     result = MAX(size.height, result); //At least one row 
    } 
    return result; 
} 

@end 

Funcionó perfectamente para mí. Tenía una Célula personalizada con 3 imágenes con tamaños fijos, 2 etiquetas con tamaños fijos y 2 etiquetas variables. Trabajado como un encanto. Espero que funcione para usted también.

Recuerdos, Alexandre.

22

Esto generalmente funciona bastante bien:

Objective-C:

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

Swift:

override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat { 
    return UITableViewAutomaticDimension; 
} 
+0

Exactamente lo que necesitaba. – adrian1kat

+5

Esto no funcionará en ios9 – Bangalore

+2

funciona con ios9, es posible que deba proporcionar la altura máxima estimada en la función de vista de tabla ** "estimatedHeightForRowAtIndexPath" ** – LuAndre

0

siempre puedo implementar esto en todas mis células en una clase de células súper porque por alguna razón UITableViewAutomaticDimension no funciona tan bien.

-(CGFloat)cellHeightWithData:(id)data{ 
    CGFloat height = [[self contentView] systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 
    [self fillCellWithData:data]; //set the label's text or anything that may affect the size of the cell 
    [self layoutIfNeeded]; 
    height = [[self contentView] systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 
    return height+1; //must add one because of the cell separator 
} 

a llamar a este método en su -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath usando una célula ficticia.

nota: esto funciona solo con autolayout, pero también funciona con ios 7 y posterior.

pd: no se olvide de marcar la casilla en la xib o guión para "anchura preferida explícita" y establecer el ancho estática (en los cmd + alt + 5 menú)

4
self.tblVIew.estimatedRowHeight = 500.0; // put max you expect here. 
self.tblVIew.rowHeight = UITableViewAutomaticDimension; 
0

Swift Use celdas y etiquetas personalizadas. Configure las restricciones para UILabel.(Arriba, izquierda, abajo, derecha) Establecer líneas de la UILabel a 0

Agregue el código siguiente en el método de la viewDidLoad ViewController:

tableView.estimatedRowHeight = 68.0 
tableView.rowHeight = UITableViewAutomaticDimension 

// Delegado & fuente de datos

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { 
    return UITableViewAutomaticDimension; 
} 
0

Tuve una prueba muy grande en UILabel. Sobre todo no funcionan, entonces yo creo categoría de cadena como de abajo y tengo la altura exacta

- (CGFloat)heightStringWithEmojifontType:(UIFont *)uiFont ForWidth:(CGFloat)width { 

// Get text 
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0); 
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef) self); 
CFIndex stringLength = CFStringGetLength((CFStringRef) attrString); 

// Change font 
CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef) uiFont.fontName, uiFont.pointSize, NULL); 
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, stringLength), kCTFontAttributeName, ctFont); 

// Calc the size 
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString); 
CFRange fitRange; 
CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(width, CGFLOAT_MAX), &fitRange); 

CFRelease(ctFont); 
CFRelease(framesetter); 
CFRelease(attrString); 

return frameSize.height + 10;} 
0

Este es uno de mi buena solución. funcionó para mí

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    cell.textLabel.text = [_nameArray objectAtIndex:indexPath.row]; 
    cell.textLabel.numberOfLines = 0; 
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping; 
} 

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

Tenemos que aplicar estos 2 cambios.

1)cell.textLabel.numberOfLines = 0; 
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping; 

2)return UITableViewAutomaticDimension; 
Cuestiones relacionadas