Problema de altura dinámica para celdas UITableView (Swift)


79

Se está inyectando texto dinámico de longitud variable en las etiquetas de las celdas de la vista de tabla. Para que las alturas de las celdas de vista de tabla tengan un tamaño dinámico, lo he implementado en viewDidLoad():

self.tableView.estimatedRowHeight = 88.0
self.tableView.rowHeight = UITableViewAutomaticDimension

Esto funciona muy bien para las celdas que aún no se han desplazado (como UITableViewAutomaticDimentionse llama al desplazarse a la celda), pero no para las celdas que se muestran inicialmente en pantalla al cargar la tabla con datos.

Intenté simplemente volver a cargar los datos (como se sugiere en muchos otros recursos):

self.tableView.reloadData()

en ambos viewDidAppear()y viewWillAppear()fue en vano. Estoy perdido ... ¿alguien sabe cómo hacer que xcode represente la altura dinámica de las celdas cargadas inicialmente en la pantalla?

Por favor, avíseme si hay un método alternativo mejor.


Si sus restricciones de altura para la (s) celda (s) están configuradas correctamente, no he visto ningún problema con esto en la naturaleza usando la versión Xcode 6.3. Incluso tenga un proyecto de muestra en github con este trabajo. github.com/darren102/DTFAutomaticCellHeight
darren102

1
Resolví este problema compensando en exceso la altura potencial de la etiqueta. Por favor vea mi respuesta a continuación. Independientemente, si tiene una mejor solución, ¡hágamelo saber!
simplexity

Respuestas:


115

Prueba esto:

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

EDITAR

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Rápido 4

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Rápido 4.2

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}

Defina ambos métodos arriba.
Resuelve el problema.

PD: Se requieren restricciones superiores e inferiores para que esto funcione.

Aquí hay un ejemplo


3
@bashan Funciona perfectamente. Asegúrese de haber dado las restricciones adecuadas.
iDhaval

2
No funciona. Parece que hay un error si una palabra es demasiado larga pero no lo suficiente, no se procesa correctamente. Si son unas pocas palabras, parece funcionar correctamente.
Jeeves

6
Esto no funcionó para mí hasta que agregué una restricción inferior. Creo que vale la pena señalar en su respuesta que se deben establecer restricciones superiores e inferiores para que esto funcione.
Mitch Downey

2
Se requieren restricciones inferiores y superiores para que esto funcione.
Antony Ouseph

2
Se requieren restricciones inferiores y superiores para los "elementos de celda" para que esto funcione
EnasAZ

37

Utilizar este:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300

y no use: heightForRowAtIndexPathfunción delegada

Además, en el guión gráfico no establezca la altura de la etiqueta que contiene una gran cantidad de datos. Dale top, bottom, leading, trailingrestricciones.


4
¡La restricción de fondo es importante! Me perdí eso y me pregunté por qué no se podía calcular la altura.
coyer

Estaba dejando atrás estoheightForRowAtIndexPath
error del servidor 500

@Javeed Creo que puedes usarlo en cualquier lugar como Static Cell o Dynamic Cell ..
ami rt

16

SWIFT 3

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 160

¡¡¡Y!!! En StoryBoard: TIENE QUE establecer restricciones SUPERIORES E INFERIORES para su etiqueta. Nada más.


11

Este extraño error se resolvió mediante los parámetros de Interface Builder ya que las otras respuestas no resolvieron el problema.

Todo lo que hice fue hacer que el tamaño de etiqueta predeterminado sea más grande de lo que podría ser el contenido y que también se refleje en la estimatedRowHeightaltura. Anteriormente, configuré la altura de fila predeterminada en Interface Builder 88pxy la reflejé así en mi controlador viewDidLoad():

self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0

Pero eso no funcionó. Entonces me di cuenta de que el contenido nunca llegaría a ser más grande de lo que quizás 100px, así que configuré la altura de celda predeterminada en 108px(más grande que el contenido potencial) y lo reflejé así en el controlador viewDidLoad():

self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 108.0

En realidad, esto permitió que el código redujera las etiquetas iniciales al tamaño correcto. En otras palabras, nunca se expandió a un tamaño más grande, pero siempre pudo encogerse ... Además, no self.tableView.reloadData()se necesitó nada adicional viewWillAppear().

Sé que esto no cubre tamaños de contenido muy variables, pero esto funcionó en mi situación donde el contenido tenía un número máximo de caracteres posible.

No estoy seguro de si esto es un error en Swift o Interface Builder, pero funciona como un encanto. ¡Darle una oportunidad!


También tengo el mismo problema. He actualizado mi respuesta. resolvió mi problema. simplemente defina solo este método y elimine todo lo relacionado con la altura.
iDhaval

8

Configure la dimensión automática para la altura de la fila y la altura estimada de la fila y asegúrese de seguir los siguientes pasos:

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Set automatic dimensions for row height
    // Swift 4.2 onwards
    table.rowHeight = UITableView.automaticDimension
    table.estimatedRowHeight = UITableView.automaticDimension


    // Swift 4.1 and below
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension

}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    // Swift 4.2 onwards
    return UITableView.automaticDimension

    // Swift 4.1 and below
    return UITableViewAutomaticDimension
}

Por ejemplo: si tiene una etiqueta en su UITableviewCell, entonces,

  • Establecer el número de líneas = 0 (& modo de salto de línea = truncar la cola)
  • Establezca todas las restricciones (superior, inferior, derecha izquierda) con respecto a su supervista / contenedor de celdas.
  • Opcional : establezca la altura mínima para la etiqueta, si desea que la etiqueta cubra el área vertical mínima, incluso si no hay datos.

Aquí hay una etiqueta de muestra con restricciones de altura dinámicas.

ingrese la descripción de la imagen aquí


1
La entrada en ViewDidLoad () mencionada por Krunal fue la solución para mí.
SHS

7

La celda de tamaño dinámico de UITableView requería 2 cosas

  1. Establecer la restricción correcta de su vista dentro de la celda de la vista de la tabla (principalmente incluye darle a su vista las restricciones superiores, inferiores y de seguimiento adecuadas)
  2. Llamar a estas propiedades de TableView en viewDidLoad ()

     tableView.rowHeight = UITableViewAutomaticDimension
    
     tableView.estimatedRowHeight = 140
    

Este es un maravilloso tutorial sobre el auto-tamaño (celdas de vista de tabla dinámica) escrito en swift 3.


6

Para Swift 3 puedes usar lo siguiente:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

3

Para Swift 4.2

@IBOutlet weak var tableVw: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Set self as tableView delegate
    tableVw.delegate = self

    tableVw.rowHeight = UITableView.automaticDimension
    tableVw.estimatedRowHeight = UITableView.automaticDimension
}

// UITableViewDelegate Method 
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    return UITableView.automaticDimension
}

Codificación feliz :)


2

Tratar

override func viewWillAppear(animated: Bool) {
    self.tableView.layoutSubviews()
}

Tuve el mismo problema y me funciona.


Lo intentaré y te haré saber lo que sucede. ¡Gracias por la sugerencia! Casi un año después de preguntar, ¡no he encontrado ninguna otra respuesta además de la mía! ¡Espero que funcione!
simplexity

asegúrese de llamar a super.viewWillAppear (animado) antes de llamar a layoutsubviews
Alan Scarpa

2

Para hacer que el tamaño automático de UITableViewCell funcione, asegúrese de estar haciendo estos cambios:

  • En Storyboard, su UITableView solo debe contener celdas de prototipo dinámico (no debe usar celdas estáticas); de lo contrario, la función de auto-tamaño no funcionará.
  • En Storyboard, su UILabel de UITableViewCell se ha configurado para las 4 restricciones que son restricciones superiores, inferiores, iniciales y finales.
  • En Storyboard, el número de líneas de UILabel de UITableViewCell debe ser 0
  • En el conjunto de funciones viewDidLoad de su UIViewController debajo de las propiedades de UITableView:

    self.tableView.estimatedRowHeight = <minimum cell height> 
    self.tableView.rowHeight = UITableViewAutomaticDimension
    

¿Cómo implementar lo mismo usando celdas estáticas?
Javeed

Después de probar todas las soluciones que se ofrecen aquí, solo esta (configurando el <minimum cell height>para estimatedRowHeight) realmente solucionó mi problema. Antes de esto, la celda tenía un tamaño automático, pero también recibía varias advertencias de restricciones. ¡Ahora no lo hago! ¡¡Muchas gracias, Anshul !!
RoberRM

2

Para Swift, verifiqué esta respuesta en iOS 9.0 y iOS 11 también (Xcode 9.3)

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

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Aquí debe agregar restricciones superior, inferior, derecha e izquierda


2

En mi caso, en el guión gráfico tenía dos etiquetas como en la imagen a continuación, ambas etiquetas tenían los valores de ancho deseados establecidos antes de igualarlos. una vez que deseleccione, cambiará a automático y, como de costumbre, tener debajo las cosas debería funcionar a la perfección.

1.rowHeight = UITableView.automaticDimension, and
2.estimatedRowHeight = 100(In my case).
3.make sure label number of lines is zero.

ingrese la descripción de la imagen aquí


2

Además de lo que otros han dicho,

¡ESTABLEZCA LAS RESTRICCIONES DE SU ETIQUETA EN RELACIÓN CON LA SUPERVISIÓN!

Entonces, en lugar de colocar las restricciones de su etiqueta en relación con otras cosas a su alrededor, limítelo a la vista de contenido de la celda de la vista de tabla.

Luego, asegúrese de que la altura de su etiqueta esté establecida en más o igual a 0, y que el número de líneas esté establecido en 0.

Luego ViewDidLoadagregue:

tableView.estimatedRowHeight = 695

tableView.rowHeight = UITableViewAutomaticDimension

¡ESTABLEZCA LAS RESTRICCIONES DE SU ETIQUETA EN RELACIÓN CON LA SUPERVISIÓN !: ¡AHORRÉ MIS HORAS! gracias.
ACAkgul

2

Esto es simple cuando se hacen 2 cosas:

  1. ajuste de la altura automática
tableView.rowHeight = UITableView.automaticDimension
  1. creando todas las TableViewCells con restricciones COMPLETAS de arriba a abajo. El último elemento DEBE definir un espacio inferior para terminar la celda.

Entonces, el motor de diseño puede calcular la altura de la celda y aplicar el valor correctamente.


1

Tu solución me inspiró y probé de otra manera.

Intente agregar tableView.reloadData()a viewDidAppear().

Esto funciona para mi.

Creo que lo que hay detrás del desplazamiento es "lo mismo" que reloadData. Cuando te desplazas por la pantalla, es como llamar reloadData()cuando viewDidAppear.

Si esto funciona, por favor responda esta respuesta para poder estar seguro de esta solución.


Lo intentaré y lo actualizaré para ver si crea la misma solución. ¡Gracias!
simplexity

Lo siento Kang, extrañamente no tuvo ningún efecto en el diseño. Los dejó con el valor estático en el que se establecieron en Interface Builder en lugar de ajustarlos al tamaño adecuado.
simplexity

1

Desafortunadamente, no estoy seguro de lo que me estaba perdiendo. Los métodos anteriores no me funcionan para obtener la altura de la celda xib o dejar que layoutifneeded () o UITableView.automaticDimension hagan el cálculo de la altura. He estado buscando e intentando durante 3 o 4 noches pero no pude encontrar una respuesta. Sin embargo, algunas respuestas aquí o en otra publicación me dieron pistas para la solución. Es un método estúpido pero funciona. Simplemente agregue todas sus celdas en una matriz. Y luego configure la salida de cada una de sus restricciones de altura en el guión gráfico de xib. Finalmente, súmalos en el método heightForRowAt. Es sencillo si no está familiarizado con esas API.

Rápido 4.2

CustomCell.Swift

@IBOutlet weak var textViewOneHeight: NSLayoutConstraint!
@IBOutlet weak var textViewTwoHeight: NSLayoutConstraint!
@IBOutlet weak var textViewThreeHeight: NSLayoutConstraint!

@IBOutlet weak var textViewFourHeight: NSLayoutConstraint!
@IBOutlet weak var textViewFiveHeight: NSLayoutConstraint!

MyTableViewVC.Swift

.
.
var myCustomCells:[CustomCell] = []
.
.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = Bundle.main.loadNibNamed("CustomCell", owner: self, options: nil)?.first as! CustomCell

.
.
myCustomCells.append(cell)
return cell

}


override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

   let totalHeight = myCustomCells[indexPath.row].textViewOneHeight.constant + myCustomCells[indexPath.row].textViewTwoHeight.constant +  myCustomCells[indexPath.row].textViewThreeHeight.constant + myCustomCells[indexPath.row].textViewFourHeight.constant + myCustomCells[indexPath.row].textViewFiveHeight.constant

  return totalHeight + 40 //some magic number


}

1

Yo uso estos

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    return 100
}

0

Simplemente debe establecer todas las restricciones para SUPERIOR , INFERIOR y ALTURA para cada objeto en la vista de celda / vistas y eliminar la posición Y media existente si tiene. Porque donde no hiciste esto, coloca artefactos en otras vistas.


3
¡Hola! Esta respuesta puede ser buena, pero es mejor proporcionar un ejemplo práctico, que explique y demuestre su respuesta.
ItamarG3

0

Para el objetivo c, esta es una de mis buenas soluciones. me ha funcionado.

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

Necesitamos aplicar estos 2 cambios.

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

2)return UITableViewAutomaticDimension;

0

También tuve este problema inicialmente, resolví mi problema con este código, intente evitar el uso de en self.tableView.reloadData()lugar de este código para la altura dinámica

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

0

Cuando uso un static UITableView, configuro todos los valores en UILabelsy luego llamo tableView.reloadData().


0
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0

Y no olvide agregar restricciones de fondo para la etiqueta


0

Swift 5 Disfruta

tablev.rowHeight = 100
tablev.estimatedRowHeight = UITableView.automaticDimension


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tablev.dequeueReusableCell(withIdentifier: "ConferenceRoomsCell") as! ConferenceRoomsCell
    cell.lblRoomName.numberOfLines = 0
    cell.lblRoomName.lineBreakMode = .byWordWrapping
    cell.lblRoomName.text = arrNameOfRooms[indexPath.row]
    cell.lblRoomName.sizeToFit()
    return cell
}

-1
self.Itemtableview.estimatedRowHeight = 0;
self.Itemtableview.estimatedSectionHeaderHeight = 0;
self.Itemtableview.estimatedSectionFooterHeight = 0;


[ self.Itemtableview reloadData];
self.Itemtableview.frame = CGRectMake( self.Itemtableview.frame.origin.x,  self.Itemtableview.frame.origin.y,  self.Itemtableview.frame.size.width,self.Itemtableview.contentSize.height + self.Itemtableview.contentInset.bottom + self.Itemtableview.contentInset.top);

Si bien este código puede resolver la pregunta, incluir una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación y probablemente resultaría en más votos a favor. Recuerde que está respondiendo la pregunta a los lectores en el futuro, no solo a la persona que pregunta ahora. Por favor, editar su respuesta para agregar explicaciones y dar una indicación de lo que se aplican limitaciones y supuestos.
Suraj Rao

-3

Establezca la restricción adecuada y actualice los métodos delegados como:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Esto resolverá el problema de la altura dinámica de la celda. SI no es necesario comprobar las limitaciones.


1
El mismo código que la respuesta de Ahmed Lotfy en esta misma página ...
Eric Aya

Hmmm, he comprobado el rápido 3. *, me perdí Ahmed ans
Kanjariya-IOS

1
también debe proporcionar la altura estimada de la fila para que el código funcione
Mohsen Shakiba
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.