Cambiar el tamaño de UITableView para adaptarse al contenido

Estoy creando una aplicación que tendrá una pregunta en UILabel y una respuesta de opción múltiple en UITableView , cada fila muestra una opción múltiple. Las preguntas y respuestas variarán, por lo que necesito que este UITableView sea ​​dynamic en altura.

Me gustaría encontrar un sizeToFit para la mesa. Donde el marco de la tabla se establece a la altura de todo su contenido.

¿Alguien puede aconsejarme sobre cómo puedo lograr esto?

En realidad, encontré la respuesta yo mismo.

Solo creo un nuevo CGRect para tableView.frame con la height de table.contentSize.height

Eso establece la altura de UITableView a la height de su contenido. Como el código modifica la interfaz de usuario, no olvide ejecutarlo en el hilo principal:

 dispatch_async(dispatch_get_main_queue(), ^{ //This code will run in the main thread: CGRect frame = self.tableView.frame; frame.size.height = self.tableView.contentSize.height; self.tableView.frame = frame; }); 

Solución Swift

Sigue estos pasos:

1- Establece la restricción de altura para la tabla desde el guión gráfico.

2- Arrastre la restricción de altura desde el guión gráfico y cree @IBOutlet para ella en el archivo del controlador de vista.

  @IBOutlet weak var tableHeight: NSLayoutConstraint! 

3- Luego puedes cambiar la altura de la tabla dinámicamente usando este código:

 override func viewWillLayoutSubviews() { super.updateViewConstraints() self.tableHeight?.constant = self.table.contentSize.height } 

Actualizar

Si la última fila está cortada para usted, intente llamar a viewWillLayoutSubviews () en la función willDisplay cell:

 func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { self.viewWillLayoutSubviews() } 

Solución Swift 4 sin KVO, DispatchQueue, estableciendo restricciones usted mismo. Esta solución se basa en la respuesta de Gulz.

1) Cree una subclase de UITableView:

 class IntrinsicTableView: UITableView { override var contentSize:CGSize { didSet { self.invalidateIntrinsicContentSize() } } override var intrinsicContentSize: CGSize { self.layoutIfNeeded() return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height) } } 

2) Agregue un UITableView a su diseño y establezca restricciones en todos los lados. Establezca la clase de este en IntrinsicTableView .

3) Debería ver algunos errores, porque Storyboard no tiene en cuenta nuestra subclase ‘ intrinsicContentSize ‘. Solucione esto abriendo el inspector de tamaño y reemplazando el intrinsicContentSize por un valor de marcador de posición. Esto es una anulación para el tiempo de diseño. En tiempo de ejecución usará la anulación en nuestra clase IntrinsicTableView

Intenté esto en iOS 7 y funcionó para mí

 - (void)viewDidLoad { [super viewDidLoad]; [self.tableView sizeToFit]; } 

Agregue un observador para la propiedad contentSize en la vista de tabla y ajuste el tamaño del marco según corresponda

 [your_tableview addObserver:self forKeyPath:@"contentSize" options:0 context:NULL]; 

luego en la callback:

 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { CGRect frame = your_tableview.frame; frame.size = your_tableview.contentSize; your_tableview.frame = frame; } 

Espero que esto te ayudará.

En caso de que no quiera seguir los cambios en el tamaño del contenido de la vista de tabla, puede encontrar esta subclase útil.

 protocol ContentFittingTableViewDelegate: UITableViewDelegate { func tableViewDidUpdateContentSize(_ tableView: UITableView) } class ContentFittingTableView: UITableView { override var contentSize: CGSize { didSet { if !constraints.isEmpty { invalidateIntrinsicContentSize() } else { sizeToFit() } if contentSize != oldValue { if let delegate = delegate as? ContentFittingTableViewDelegate { delegate.tableViewDidUpdateContentSize(self) } } } } override var intrinsicContentSize: CGSize { return contentSize } override func sizeThatFits(_ size: CGSize) -> CGSize { return contentSize } } 

Tenía una vista de tabla dentro de la vista de desplazamiento y tuve que calcular la altura de tableView y cambiar su tamaño en consecuencia. Esos son los pasos que he tomado:

0) agregue un UIView a su scrollView (probablemente funcione sin este paso, pero lo hice para evitar cualquier posible conflicto) – esta será una vista de contenedor para su vista de tabla. Si sigue este paso, establezca las fronteras de las vistas a la derecha de las vistas de tabla.

1) crear una subclase de UITableView:

 class IntrinsicTableView: UITableView { override var contentSize:CGSize { didSet { self.invalidateIntrinsicContentSize() } } override var intrinsicContentSize: CGSize { self.layoutIfNeeded() return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height) } } 

2) establecer la clase de una vista de tabla en Storyboard a IntrinsicTableView: captura de pantalla: http://joxi.ru/a2XEENpsyBWq0A

3) Establezca el heightConstraint en su vista de tabla

4) arrastre el IBoutlet de su tabla a su ViewController

5) arrastre el IBoutlet de la restricción de altura de su tabla a su ViewController

6) agregue este método en su ViewController:

 override func viewWillLayoutSubviews() { super.updateViewConstraints() self.yourTableViewsHeightConstraint?.constant = self.yourTableView.intrinsicContentSize.height } 

Espero que esto ayude

Swift 3, iOS 10.3

Solución 1: simplemente ponga self.tableview.sizeToFit() en la función cellForRowAt indexPath . Asegúrese de establecer la altura de la vista de tabla más alta que la que necesita. Esta es una buena solución si no tiene vistas debajo de la vista de tabla. Sin embargo, si lo tiene, la restricción de la tabla de abajo no se actualizará (no intenté solucionarlo porque se me ocurrió la solución 2)

Ejemplo:

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as? TestCell { cell.configureCell(data: testArray[indexPath.row]) self.postsTableView.sizeToFit() return cell } return UITableViewCell() } 

Solución 2: establezca la restricción de altura de la tabla en el guión gráfico y arrástrela al ViewController. Si conoce la altura promedio de su celda y sabe cuántos elementos contiene su matriz, puede hacer algo como esto:

 tableViewHeightConstraint.constant = CGFloat(testArray.count) * 90.0 // Let's say 90 is the average cell height 

*EDITAR:

Después de todas las soluciones que probé y cada una de ellas solucionaba algo, pero no del todo, esta es la respuesta que explica y soluciona este problema por completo.

La respuesta de Mimo y la respuesta de Anooj VM son impresionantes, pero hay un pequeño problema si tienes una lista grande, es posible que la altura del marco corte algunas de tus celdas.

Asi que. He modificado la respuesta un poco:

 dispatch_async(dispatch_get_main_queue()) { //This code will run in the main thread: CGFloat newHeight=self.tableView.contentSize.height; CGFloat screenHeightPermissible=(self.view.bounds.size.height-self.tableView.frame.origin.y); if (newHeight>screenHeightPermissible) { //so that table view remains scrollable when 'newHeight' exceeds the screen bounds newHeight=screenHeightPermissible; } CGRect frame = self.tableView.frame; frame.size.height = newHeight; self.tableView.frame = frame; } 

Hay una manera mucho mejor de hacerlo si usa AutoLayout: cambie la restricción que determina la altura. Simplemente calcule el alto de los contenidos de su tabla, luego encuentre la restricción y cámbiela. Aquí hay un ejemplo (suponiendo que la restricción que determina la altura de su tabla es en realidad una restricción de altura con la relación “Igual”):

 override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) for constraint in tableView.constraints { if constraint.firstItem as? UITableView == tableView { if constraint.firstAttribute == .height { constraint.constant = tableView.contentSize.height } } } } 

En caso de que su contentSize no sea correcto, esto se debe a que se basa en el valor estimado de RowHeight (automático), utilícelo antes

tableView.estimatedRowHeight = 0;

fuente: https://forums.developer.apple.com/thread/81895

objc versión de Musa almatri

 (void)viewWillLayoutSubviews { [super updateViewConstraints]; CGFloat desiredHeight = self.tableView.contentSize.height; // clamp desired height, if needed, and, in that case, leave scroll Enabled self.tableHeight.constant = desiredHeight; self.tableView.scrollEnabled = NO; } 

Puedes probar esta vista AGTableView personalizada

Para establecer una restricción de altura de la vista de tabla usando el guión gráfico o mediante progtwigción. (Esta clase recupera automáticamente una restricción de altura y establece la altura de la vista del contenido en la altura de vista de la pantalla).

 class AGTableView: UITableView { fileprivate var heightConstraint: NSLayoutConstraint! override init(frame: CGRect, style: UITableViewStyle) { super.init(frame: frame, style: style) self.associateConstraints() } required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.associateConstraints() } override open func layoutSubviews() { super.layoutSubviews() if self.heightConstraint != nil { self.heightConstraint.constant = self.contentSize.height } else{ self.sizeToFit() print("Set a heightConstraint to Resizing UITableView to fit content") } } func associateConstraints() { // iterate through height constraints and identify for constraint: NSLayoutConstraint in constraints { if constraint.firstAttribute == .height { if constraint.relation == .equal { heightConstraint = constraint } } } } } 

Nota Si hay algún problema para establecer una Altura, entonces yourTableView.layoutSubviews() .

Como una extensión de la respuesta de Anooj VM, sugiero lo siguiente para actualizar el tamaño del contenido solo cuando cambie.

Este enfoque también deshabilita el desplazamiento correctamente y admite listas más grandes y rotación . No es necesario dispatch_async porque los cambios de contentSize se envían en el hilo principal.

 - (void)viewDidLoad { [super viewDidLoad]; [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:NULL]; } - (void)resizeTableAccordingToContentSize:(CGSize)newContentSize { CGRect superviewTableFrame = self.tableView.superview.bounds; CGRect tableFrame = self.tableView.frame; BOOL shouldScroll = newContentSize.height > superviewTableFrame.size.height; tableFrame.size = shouldScroll ? superviewTableFrame.size : newContentSize; [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ self.tableView.frame = tableFrame; } completion: nil]; self.tableView.scrollEnabled = shouldScroll; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([change[NSKeyValueChangeKindKey] unsignedIntValue] == NSKeyValueChangeSetting && [keyPath isEqualToString:@"contentSize"] && !CGSizeEqualToSize([change[NSKeyValueChangeOldKey] CGSizeValue], [change[NSKeyValueChangeNewKey] CGSizeValue])) { [self resizeTableAccordingToContentSize:[change[NSKeyValueChangeNewKey] CGSizeValue]]; } } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; [self resizeTableAccordingToContentSize:self.tableView.contentSize]; } - (void)dealloc { [self.tableView removeObserver:self forKeyPath:@"contentSize"]; } 

Solución Mu para esto en swift 3 : llame a este método en viewDidAppear

 func UITableView_Auto_Height(_ t : UITableView) { var frame: CGRect = t.frame; frame.size.height = t.contentSize.height; t.frame = frame; } 

Establecer propiedades de vista de tabla para

 tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = 100 

Y en la celda de vista de tabla, configure la propiedad de su etiqueta numberOfLines = 0

establezca las restricciones superior, inferior, izquierda, derecha de su etiqueta en las restricciones superior, inferior, izquierda, derecha de la etiqueta ** Calculará la altura automáticamente