Cambiar el tamaño del encabezado UITableView Y que contiene UITextView (iOS7 + AutoLayout)

He estado luchando con esto ahora por un time, y quiero asegurarme de que estoy haciendo esto de la manera correcta. Como reference, estoy usando AutoLayout con Storyboards, y es una aplicación con solo iOS7.

Tengo una UITableView con una vista de encabezado, y la interfaz de usuario de HeaderView está conectada en el guión gráfico. Dejé el encabezado en el guión gráfico y contiene algunos elementos, uno de los cuales es una UITextView no desplazable.

Aquí hay una captura de pantalla de cómo se ve básicamente en el guión gráfico:

captura de pantalla

Oscurecí el background de la vista del encabezado a un gris más oscuro para que destaque.

El text de UITextView puede ser dynamic, por lo que su altura debe cambiar según el tamaño del text. Pero la parte difícil es que la vista de encabezado de la tabla también necesita ajustar su altura, dependiendo del tamaño de este text. He intentado algunas cosas diferentes con restricciones, pero en realidad no funciona correctamente (a less que desactive AutoLayout y vuelva a clasificar las cosas de manera programática, lo que realmente me gustaría evitar).

Quiero que esto sea lo más limpio posible con tan poco código como sea necesario, por supuesto. No estoy vinculado a usar el encabezado de vista de tabla, aunque funciona bien con mis necesidades, ya que lo quiero y su vista de text contiene desplazarse con los detalles reales a continuación. Pero dicho todo, si hay un enfoque más simple para lograr esto (es decir, con una uilabel), con gusto cambiaré la estructura subyacente.

¿Alguna idea de un enfoque? No busco a alguien para sostener mi mano a través de una respuesta; solo buscando principalmente algunos buenos puntos de partida si es posible. ¡Gracias por adelantado!

Hace un time encontré una nueva solución, tal vez necesite ajustar las animaciones y es experimental, pero, para algunos casos, está bien, así que pruébalo:

  1. Agregue una vista de encabezado a un UITableView.
  2. Agregue una subvista a headerView, llamémosle contenedor.
  3. Haga que la altura del envoltorio se ajuste con sus subidas (a través del layout automático).
  4. Cuando la reproducción automática ha finalizado el layout, establezca la altura de headerView a la altura del envoltorio. (ver -updateTableViewHeaderViewHeight )
  5. Vuelva a configurar headerView. (ver -resetTableViewHeaderView )

Aquí hay un código:

 - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; [self updateTableViewHeaderViewHeight]; } /** tableView's tableViewHeaderView contains wrapper view, which height is evaluated with Auto Layout. Here I use evaluated height and update tableView's tableViewHeaderView's frame. New height for tableViewHeaderView is applied not without magic, that's why I call -resetTableViewHeaderView. And again, this doesn't work due to some internals of UITableView, so -resetTableViewHeaderView call is scheduled in the main run loop. */ - (void)updateTableViewHeaderViewHeight { // get height of the wrapper and apply it to a header CGRect Frame = self.tableView.tableHeaderView.frame; Frame.size.height = self.tableHeaderViewWrapper.frame.size.height; self.tableView.tableHeaderView.frame = Frame; // this magic applies the above changes // note, that if you won't schedule this call to the next run loop iteration // you'll get and error // so, I guess that's not a clean solution and could be wrapped in @try@catch block [self performSelector:@selector(resetTableViewHeaderView) withObject:self afterDelay:0]; } // yeah, guess there's something special in the setter - (void)resetTableViewHeaderView { // whew, this could be animated! [UIView beginAnimations:@"tableHeaderView" context:nil]; self.tableView.tableHeaderView = self.tableView.tableHeaderView; [UIView commitAnimations]; } 

Todo esto funciona perfectamente después del pase inicial de reproducción automática. Más tarde, si cambia el contenido del contenedor para que obtenga una altura diferente, no funcionará por algún motivo (supongamos que la colocación de UILabel requiere varios pasos de autoplayout o algo así). Resolví esto con la progtwigción setNeedsLayout para la vista ViewController en la siguiente iteración de ciclo de ejecución.

He creado un proyecto de ejemplo para eso: TableHeaderView + Autolayout .

Sugeriría establecer la altura de manera programática. Puede calcular la altura de la vista de text con boundingRectWithSize: options: context

Luego simplemente establece el marco de tableViewHeader.

Como se dijo anteriormente, en UITableView la altura para el encabezado no está controlada por el layout automático sino por

 -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 

La altura del pie de página se establece por

 -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 

Y, finalmente, la altura de la celda se establece por

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

La vista de tabla carga las celdas de storyboards, files XIB o código. Utiliza los methods anteriores para establecer el tamaño del marco para los encabezados, pies de página y celdas, y dimensiona sus vistas para que se adapten a ese espacio.

Es importante comprender que el layout automático no cambiará esos tamaños, solo maneja las reglas utilizadas para diseñar las vistas dentro de sus contenedores.

Si sus células / encabezados / pies de página usan tamaños estáticos, entonces es muy fácil. Simplemente bloquea las alturas de todas tus subvenciones, configura tu celda para que sea del mismo tamaño que regresas en altura, para … y todo se ve como debería.

Las celdas / encabezados / pies de página dinámicas requieren un poco más de trabajo.

Esencialmente, se le pide que le diga a tableview el tamaño de su celda / encabezado / pie de página ANTES de que realmente lo haya hecho y haya dimensionado todas las subvistas.

Puede probar esto rápidamente estableciendo un punto de interrupción en los methods cellForRowAtIndexPath y heightForRowAtIndexPath, primero se llama a la altura.

Para alturas dinámicas de celda de tabla, un truco común es crear una celda única en viewDidLoad y guárdelo para calcular las alturas. Luego, cuando llegue a heightForRowAtIndexPath o heightForHeaderInSection, utilice la celda pre hecha para poner los valores que utilizará en la celda final, para que UILabels use sizeWithFont (pre iOS 7) o boundingRectWithSize (iOS 7.0+) y sizeThatFits para UITextViews. (Para cualquiera que lea esto en el futuro, verifique que esos methods no hayan sido reemplazados por algo más nuevo)

Por lo tanto, obtenga el text que desee en la celda ficticia, obtenga las alturas de las tags y las vistas de text, agregue los espacios entre ellas y devuelva el tamaño final cuando termine.

Luego en cellForRowAtIndexPath o headerForSection rehacer la configuration de valores, pero en la celda real que se mostrará.

Si sus cálculos de altura coinciden con la configuration de layout automático, todo encajará perfectamente en el espacio creado para ello.

Si desea cambiar la altura de una celda o encabezado después de que ya esté dibujada, entonces querrá actualizar la vista de tabla haciendo algo como:

 [self.tableView beginUpdates]; // change the data that will cause cell height to be different in heightForCellAtIndexPath or which will change a header or footer height calculation [self.tableView endUpdates]; 

Esto hará que la vista de tabla verifique los tamaños que tiene y solo actualizará las celdas o el encabezado / pie de página si se cambia.

Se proporciona una vista de encabezado de vista de tabla a una vista de tabla mediante el método tableView: viewForHeaderInSection: delegate.

 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // create your header view here (read the docs on this method, there are some specific requirements)... } 

No sé si es posible diseñar la vista del encabezado en el guión gráfico; Supongo que tendría que usar un file XIB individual o hacerlo mediante progtwigción.

En otras palabras, creo que te diriges hacia la creación de restricciones en el código si necesitas proporcionar vistas de encabezado de vista de tabla.

Por otro lado, tal vez no necesite una vista de encabezado de vista de tabla. Tal vez, lo que buscas es solo una subvista sobre la vista de la tabla que no se mueve cuando el usuario desplaza la tabla. Para hacerlo, debe volver a trabajar en su jerarquía de vista en IB. En este momento, su llamada vista de encabezado se encuentra dentro de la vista de la tabla. No quieres eso

O bien, dado que parece que está utilizando celdas estáticas, puede hacer que la celda estática superior tome la apariencia de su llamada vista de encabezado.