Cambiar el comportamiento de desplazamiento predeterminado del encabezado de sección de UITableView

Tengo una UITableView con dos secciones. Es una vista de tabla simple. Estoy usando viewForHeaderInSection para crear vistas personalizadas para estos encabezados. Hasta aquí todo bien.

El comportamiento de desplazamiento predeterminado es que cuando se encuentra una sección, el encabezado de la sección permanece anclado debajo de la barra de navegación, hasta que la siguiente sección se desplaza a la vista.

Mi pregunta es: ¿puedo cambiar el comportamiento predeterminado para que los encabezados de las secciones NO permanezcan anclados en la parte superior, sino que se desplacen por debajo de la barra de navegación con el rest de las filas de la sección?

¿Me estoy perdiendo algo obvio?

Gracias.

La forma en que resolvió este problema es ajustar el contentOffset acuerdo con el contentInset en UITableViewControllerDelegate (extiende UIScrollViewDelegate ) de esta manera:

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat sectionHeaderHeight = 40; if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) { scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0); } else if (scrollView.contentOffset.y>=sectionHeaderHeight) { scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0); } } 

El único problema aquí es que pierde un poco de rebote cuando se desplaza de regreso a la parte superior.


{NOTA: el “40” debe ser la altura exacta de SU encabezado de sección 0. Si usa un número que es más grande que la altura del encabezado de su sección 0, verá que la sensación del dedo se ve afectada (pruebe como “1000” y verá que el comportamiento del rebote es algo extraño en la parte superior). si el número coincide con la altura del encabezado de su sección 0, la sensación del dedo parece ser perfecta o casi perfecta.}

También puede agregar una sección con cero filas en la parte superior y simplemente usar el pie de página de la sección anterior como encabezado para el siguiente.

Si yo hiciera esto, aprovecharía el hecho de que UITableViews en el estilo simple tienen los encabezados fijos y los que están en el estilo agrupado no. Probablemente al menos intentaré usar una celda de tabla personalizada para imitar la apariencia de las células normales en una tabla agrupada.

En realidad no lo he intentado así que puede que no funcione, pero eso es lo que sugiero que hagas.

Sé que llega tarde, ¡pero he encontrado la solución definitiva!

Lo que quiere hacer es si tiene 10 secciones, deje que dataSource devuelva 20. Use números pares para los encabezados de las secciones, y los números impares para el contenido de la sección. algo como esto

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (section%2 == 0) { return 0; }else { return 5; } } -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { if (section%2 == 0) { return [NSString stringWithFormat:@"%i", section+1]; }else { return nil; } } 

Voilá! :RE

Hay varias cosas que se deben hacer para resolver este problema de una manera no hacky:

  1. Establezca el estilo de vista de tabla en UITableViewStyleGrouped
  2. Establezca la vista de tabla backgroundColor en [UIColor clearColor]
  3. Establezca la vista de backgroundView en cada celda de vista de tabla en una vista vacía con backgroundColor [UIColor clearColor]
  4. Si es necesario, configure la vista de tabla rowHeight apropiadamente o anule tableView:heightForRowAtIndexPath: si las filas individuales tienen diferentes alturas.

Originalmente publicado Aquí , una solución rápida usando el IB. Lo mismo se puede hacer mediante progtwigción, aunque de manera bastante simple.

Una forma probablemente más fácil de lograr esto (usando IB):

Arrastre una UIView en su TableView para convertirla en su vista de encabezado.

  1. Establezca esa altura de vista de encabezado a 100 px
  2. Establezca el contenido de la vista de tabla Insertar (arriba) en -100
  3. Los encabezados de sección ahora se desplazarán como cualquier celda normal.

Algunas personas comentaron diciendo que esta solución oculta el primer encabezado, sin embargo, no he notado ningún problema. Funcionó perfectamente para mí y fue, de lejos, la solución más simple que he visto hasta ahora.

No estaba contento con las soluciones descritas aquí hasta ahora, así que traté de combinarlas. El resultado es el siguiente código, inspirado en @awulf y @cescofry. Funciona para mí porque no tengo ningún encabezado de vista de tabla real. Si ya tiene un encabezado de vista de tabla, es posible que deba ajustar la altura.

 // Set the edge inset self.tableView.contentInset = UIEdgeInsetsMake(-23.0f, 0, 0, 0); // Add a transparent UIView with the height of the section header (ARC enabled) [self.tableView setTableHeaderView:[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 23.0f)]]; 

Simplemente cambie el estilo de TableView:

 self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped]; 

Documentación UITableViewStyle :

UITableViewStylePlain- Una vista de tabla simple. Los encabezados o pies de página de cada sección se muestran como separadores en línea y flotan cuando se desplaza la vista de tabla.

UITableViewStyleGrouped: una vista de tabla cuyas secciones presentan distintos grupos de filas. Los encabezados y pies de página de la sección no flotan.

Seleccione el estilo agrupado de TableView

Seleccione el estilo de Vista de tabla agrupada desde el Inspector de atributos de tableView en el guión gráfico.

Cambie su estilo TableView:

 self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped]; 

Según la documentación de apple para UITableView:

UITableViewStylePlain- Una vista de tabla simple. Los encabezados o pies de página de cada sección se muestran como separadores en línea y flotan cuando se desplaza la vista de tabla.

UITableViewStyleGrouped: una vista de tabla cuyas secciones presentan distintos grupos de filas. Los encabezados y pies de página de la sección no flotan. Espero que este pequeño cambio te ayude …

Establezca el headerView de la tabla con una vista transparente con la misma altura del encabezado en la vista de sección. También inicie la vista de tabla con un marco ay en-altura.

 self.tableview = [[UITableView alloc] initWithFrame:CGRectMake(0, - height, 300, 400)]; UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)] autorelease]; [self.tableView setTableHeaderView:headerView]; 

Encontré una solución alternativa, uso la primera celda de cada sección en lugar de una sección de encabezado real, esta solución no parece tan limpia, pero funciona tan bien, puedes usar una celda de prototipo definida para la sección de encabezados y en el método cellForRowAtIndexPath pregunte por indexPath.row == 0, si es verdadero, use la celda del prototipo de la sección del encabezado; de lo contrario, use su celda de prototipo predeterminada.

Ahora que el estilo agrupado se ve básicamente igual que el estilo simple en iOS 7 (en términos de planeidad y fondo), para nosotros la mejor y más fácil (es decir, menos hacky) solución era simplemente cambiar el estilo de la vista de tabla a agrupado. Jacking con contentInsets siempre fue un problema cuando integramos una barra de navegación desplazable en la parte superior. Con un estilo de vista de tabla agrupada, se ve exactamente igual (con nuestras celdas) y los encabezados de sección permanecen fijos. Sin rarezas de desplazamiento.

Asigne un recuadro negativo a su tableView. Si tiene encabezados de sección alta de 22 píxeles, y no desea que estén pegajosos, justo después de volver a cargar los datos, agregue:

 self.tableView.contentInset = UIEdgeInsetsMake(-22, 0, 0, 0); self.tableView.contentSize = CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height+22); 

Funciona como un encanto para mí. También funciona para pies de página de sección, solo asigna el recuadro negativo en la parte inferior.

Agrego la tabla a una vista de desplazamiento y parece funcionar bien.

Mira mi respuesta aquí . Esta es la forma más fácil de implementar los encabezados de sección no flotante sin ningún tipo de pirateo.

La respuesta de @LocoMike fue la más adecuada para mi TableView, sin embargo, también se rompió al usar los pies de página. Por lo tanto, esta es la solución corregida al usar encabezados y pies de página:

 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return (self.sections.count + 1) * 3; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (section % 3 != 1) { return 0; } section = section / 3; ... } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { if (section % 3 != 0) { return nil; } section = section / 3; ... } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { if (section % 3 != 0) { return 0; } section = section / 3; ... } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { if (section % 3 != 2) { return 0; } section = section / 3; ... } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { if (section % 3 != 0) { return nil; } section = section / 3; ... } - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { if (section % 3 != 2) { return nil; } section = section / 3; ... } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { int section = indexPath.section; section = section / 3; ... } 

Cambie su estilo TableView:

 self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped]; 

Según la documentación de apple para UITableView:

 UITableViewStylePlain- A plain table view. Any section headers or footers are displayed as inline separators and float when the table view is scrolled. UITableViewStyleGrouped- A table view whose sections present distinct groups of rows. The section headers and footers do not float. Hope this small change will help you .. 

¡La versión Swift de @awulf answer, que funciona genial!

 func scrollViewDidScroll(scrollView: UIScrollView) { let sectionHeight: CGFloat = 80 if scrollView.contentOffset.y <= sectionHeight { scrollView.contentInset = UIEdgeInsetsMake( -scrollView.contentOffset.y, 0, 0, 0) }else if scrollView.contentOffset.y >= sectionHeight { scrollView.contentInset = UIEdgeInsetsMake(-sectionHeight, 0, 0, 0) } } 

Aprendí que solo establecer la propiedad tableHeaderView lo hace, es decir:

  tableView.tableHeaderView = customView; 

y eso es.