Cómo ocultar el encabezado de la primera sección en UITableView (estilo agrupado)

108

Como el diseño de las vistas de tabla que utilizan el estilo agrupado cambió considerablemente con iOS 7, me gustaría ocultar (o eliminar) el encabezado de la primera sección. Hasta ahora no he logrado lograrlo.

Algo simplificado, mi código se ve así:

- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section == 0)
        return 0.0f;
    return 32.0f;
}

- (UIView*) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        UIView* view = [[UIView alloc] initWithFrame: CGRectMake(0.0f, 0.0f, 640.0f, 0.0f)];
        return view;
    }
    return nil;
}

- (NSString*) tableView:(UITableView *) tableView titleForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return nil;
    } else {
        // return some string here ...
    }
}

Si devuelvo una altura de 0, los otros dos métodos nunca serán llamados con el índice de sección 0. Sin embargo, un encabezado de sección vacío todavía se dibuja con la altura predeterminada. (En iOS 6, se llaman los dos métodos. Sin embargo, el resultado visible es el mismo).

Si devuelvo un valor diferente, el encabezado de la sección obtiene la altura especificada.

Si devuelvo 0.01, es casi correcto. Sin embargo, cuando enciendo "Color de imágenes desalineadas" en el simulador, marca todas las celdas de la vista de tabla (lo que parece ser una consecuencia lógica).

Las respuestas a la pregunta UITableView: ocultar el encabezado de la sección vacía parecen indicar que algunas personas lograron ocultar el encabezado de la sección. Pero podría aplicarse al estilo simple (en lugar del agrupado).

El mejor compromiso hasta ahora es devolver la altura 0.5, lo que resulta en una línea algo más gruesa debajo de la barra de navegación. Sin embargo, agradecería que alguien supiera cómo se puede ocultar completamente el encabezado de la primera sección.

Actualizar

Según el análisis de caglar ( https://stackoverflow.com/a/19056823/413337 ), el problema solo surge si la vista de tabla está contenida en un controlador de navegación.

Codo
fuente
No obtuve esa parte => if (section == 0) return view; return nil; es decir, devolver una vista cuando es la primera sección y nula en caso contrario
Zen
La idea es devolver una vista con una altura de 0 para la primera sección y devolver nil para todas las demás secciones para que la vista de tabla use la vista de encabezado predeterminada para ellas. La parte cero funciona muy bien; la vista de tabla muestra un encabezado para estas secciones. Pero la parte de la sección 0 es irrelevante porque nunca se llama al método con section == 0.
Codo
1
Esta respuesta parece ser corta y dulce. stackoverflow.com/a/23955420/3965
Mr Rogers

Respuestas:

154

Tengo una solución que me parece razonablemente limpia. Entonces estoy respondiendo mi propia pregunta.

Dado que 0 como la altura del encabezado de la primera sección no funciona, devuelvo 1. Luego utilizo contentInset para ocultar esa altura debajo de la barra de navegación.

C objetivo:

- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section == 0)
            return 1.0f;
    return 32.0f;
}

- (NSString*) tableView:(UITableView *) tableView titleForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return nil;
    } else {
        // return some string here ...
    }
}

- (void) viewDidLoad
{
    [super viewDidLoad];

     self.tableView.contentInset = UIEdgeInsetsMake(-1.0f, 0.0f, 0.0f, 0.0);
}

Rápido:

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return section == 0 ? 1.0 : 32
}

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.contentInset = UIEdgeInsets(top: -1, left: 0, bottom: 0, right: 0)
}
Codo
fuente
6
Usar una altura de encabezado de 0.1f es aún mejor para ocultarlo.
Chuck Krutsinger
4
Intenté usar 0.1f. Pero el resultado es que los dibujos ya no están alineados con los píxeles, lo que provoca desenfoques y reduce el rendimiento. Pruébelo en el simulador: tiene una opción para resaltar la alineación problemática.
Codo
31
En realidad, se utiliza una mejor implementación (es menos probable que se rompa en el futuro) en CGFLOAT_MINlugar de un valor codificado. En otras palabras, no lo hagas return 1.0fo 0.1f, en cambio, return CGFLOAT_MINsi Apple alguna vez cambia el valor mínimo aceptable, tendrás un código para cambiar si codificas el valor de retorno. Además, ya no sabe si está utilizando el valor más pequeño posible. Usando la constante definida, tiene la garantía de usar el valor más pequeño posible y su código sobrevivirá a los cambios del sistema operativo.
Chris Ostmo
11
@Chris: Me temo que no entendiste la idea. No devuelvo un valor muy pequeño sino un múltiplo del tamaño de un píxel para que el dibujo permanezca alineado con los píxeles (para un buen rendimiento y nitidez). Luego lo compensé usando el recuadro de contenido. Es poco probable que esto cambie en el futuro, ya que es una distancia visible considerable y no es algo que el sistema operativo pueda ignorar.
Codo
8
+1 Por no utilizar valores de píxeles fraccionarios como compensaciones de la interfaz de usuario.
Ricardo Sanchez-Saez
52

Así es como se oculta el encabezado de la primera sección en UITableView (estilo agrupado).

Solución Swift 3.0 y Xcode 8.0

  1. El delegado de TableView debe implementar el método heightForHeaderInSection

  2. Dentro del método heightForHeaderInSection, devuelve el número menos positivo. (¡no cero!)

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    
        let headerHeight: CGFloat
    
        switch section {
        case 0:
            // hide the header
            headerHeight = CGFloat.leastNonzeroMagnitude
        default:
            headerHeight = 21
        }
    
        return headerHeight
    }
usuario3378170
fuente
6
devolver CGFloat.leastNonzeroMagnitude en lugar de 0 me ayudó. ¡Gracias!
anoo_radha
Respuesta perfecta, gracias
Pierre
Por cierto, CGFLOAT_MINpara objc es idéntico a CGFloat.leastNonzeroMagnitudeen Swift
DawnSong
36

La respuesta fue muy divertida para mí y mi equipo, y funcionó a las mil maravillas.

  • En Interface Builder, simplemente mueva la vista de tabla a otra vista en la jerarquía de vistas.

RAZÓN:

Observamos que esto sucede solo para la Primera Vista en la Jerarquía de Vistas, si esta primera vista es una UITableView . Entonces, todos los otros UITableViews similares no tienen esta sección molesta, excepto la primera. Intentamos mover UITableView fuera del primer lugar en la jerarquía de vistas y todo funcionó como se esperaba.

Giorgos Ath
fuente
1
¿Todavía tiene el efecto de vidrio esmerilado de la barra de navegación cuando se desplaza por la vista de tabla?
Codo
Tendrá este efecto de desenfoque cuando configure su tableView en consecuencia. Debería configurar, contentInsetpor ejemplo, {0, 64, 0, 0}para tener el desplazamiento de 64 píxeles desde la parte superior (barra de estado más barra de navegación). El tableView debe adjuntarse en la parte superior de la pantalla, no en la topLayoutGuide (para que llegue debajo de la barra de navegación)
Julian F.Weinert
Si no está utilizando pull para actualizar, esto se verá bien.
Michael
2
Guau. Esto funcionó para mí en iOS 9 y me dejó alucinado.
asignar el
Esta debería ser la respuesta aceptada. ¡Qué error tan extraño!
Oded Harth
25

Utilice este truco para tableView de tipo agrupado

Copie y pegue el código siguiente para su vista de tabla en el método viewDidLoad :

tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, tableView.bounds.size.width, 0.01f)];
Nitesh Borad
fuente
No lo he probado, pero sospecho que esta solución tiene la misma desventaja que algunas de las otras soluciones propuestas: los dibujos ya no están alineados con los píxeles, lo que provoca desenfoques y reduce el rendimiento. El simulador puede revelarlo: tiene una opción para resaltar la alineación problemática. Sin embargo, si se redondea a 0, entonces es una buena solución.
Codo
Sí, supongo que se redondea a 0. Porque lo usé muchas veces, pero no encontré ningún desenfoque en los dibujos.
Nitesh Borad
TableHeaderView y vista de encabezado de sección? cuál es la diferencia,
AsifHabib
O ligeramente más corto: _tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 1)].
mojuba
@AsifHabib: tableHeaderView se coloca en la parte superior de todos los elementos de la tabla. Es la vista de encabezado de la tabla en sí. Y la vista del encabezado de la sección es la vista que se colocará en cada sección. Puede haber muchas vistas de encabezado de sección según el número especificado de secciones en la tabla. Pero, solo habrá una vista de encabezado de tabla.
Nitesh Borad
21

de esta manera está bien.

override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    if section == 0 {
        return CGFloat.min
    }
    return 25
}

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if section == 0 {
        return nil
    }else {
        ...
    }
}
TonnyTao
fuente
2
Esta es una buena variación de mi solución, excepto que usa valores fraccionarios. De esa manera, el texto y las imágenes ya no se alinean con los píxeles, el dibujo se ralentiza y el resultado puede volverse borroso. El simulador tiene la opción "Color de imágenes desalineadas" para revelar este problema.
Codo
Funciona bien para personas como yo que usan celdas estáticas con un containerView
thibaut noah
3
Swift 3> 'CGFloat.min' ha sido renombrado a 'CGFloat.leastNormalMagnitude'
rjobidon
6

Copié tu código y lo intenté. Funciona normalmente (probado en simulador). Adjunto vista de resultados. Quieres esa vista, ¿verdad? ¿O entendí mal tu problema?

ingrese la descripción de la imagen aquí

caglar
fuente
1
Sí, eso es básicamente lo que quiero, excepto que mi vista de tabla está en un controlador de navegación. ¿Podría hacer eso la diferencia?
Codo
2
Agregué tableView al controlador de navegación y aparece su situación :) Creo que en iOS 7, esta altura del encabezado se corrige de forma predeterminada en la vista de tabla de estilo agrupada. Al cambiar el marco de tableView, se puede ocultar la primera vista del encabezado (como set x = 0 y = -40). Sin embargo, sé que esta solución no es una buena solución.
caglar
1
Muchas gracias por tu trabajo. Entonces, parece que el problema solo surge si la vista de tabla usa el estilo agrupado y está contenida dentro de un controlador de navegación.
Codo
Al intentar cambiar de viewcontroller a tableviewcontroller, no pude solucionar el problema con el encabezado. Quizás me falta algo al intentar convertirlo. (iOS 7.0.3 sim)
Evgeni Petrov
1
¡Este problema también aparece en esta instantánea! la celda 0 no comienza desde x: 0.0f & y: 0.0f.
Burhanuddin Sunelwala
6

Swift3: heightForHeaderInSection funciona con 0, solo tiene que asegurarse de que el encabezado esté configurado en clipsToBounds.

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
       return 0
}

si no establece clipsToBounds, el encabezado oculto será visible al desplazarse.

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    guard let header = view as? UITableViewHeaderFooterView else { return }

    header.clipsToBounds = true
}
h.martin
fuente
1
clipsToBound = true es muy importante si planea ocultar completamente la vista del encabezado de la sección. Establecer su altura en 0 / CGFLOAT_MIN no es suficiente.
Altimac
5

Actualización [19/9/17]: La respuesta anterior ya no me funciona en iOS 11. Gracias Apple. Lo siguiente hizo:

self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
self.tableView.estimatedSectionHeaderHeight = 20.0f;
self.tableView.contentInset = UIEdgeInsetsMake(-18.0, 0.0f, 0.0f, 0.0);

Respuesta anterior:

Según lo publicado en los comentarios de Chris Ostomo, lo siguiente funcionó para mí:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return CGFLOAT_MIN; // to get rid of empty section header
}
Manindra Moharana
fuente
Sospecho que el contenido de la vista de tabla ya no está alineado con los píxeles, lo que provoca desenfoques y reduce el rendimiento. El simulador puede revelarlo: tiene una opción para resaltar la alineación problemática. Sin embargo, si se redondea a 0, entonces es una buena solución.
Codo
No, no noté ningún problema de contenido. Las restricciones parecían estar bien.
Manindra Moharana
1
¡Welp! ¡Ya no funciona en iOS 11! Mi solución duró menos de una semana .. 😞
Manindra Moharana
4

A continuación se explica cómo deshacerse del encabezado de la sección superior en un UITableView agrupado, en Swift:

tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))
Harris
fuente
3

En Swift 4.2 y muchas versiones anteriores, en lugar de establecer la altura del primer encabezado en 0 como en las otras respuestas, puede establecer los otros encabezados en nil. Supongamos que tiene dos secciones y solo desea que la segunda (es decir, 1) tenga un encabezado. Ese encabezado tendrá el texto Foobar :

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return section == 1 ? "Foobar" : nil
}
JaneGoodall
fuente
3

Pruebe esto si desea eliminar todo el encabezado de la sección por completo

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return CGFloat.leastNormalMagnitude
}

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return CGFloat.leastNormalMagnitude
}
Avinash
fuente
Eso es solo lo que necesito. Una solución sencilla y sencilla. 1+
iGhost
0

No puedo comentar todavía, pero que me gustaría añadir que si usted tiene una UISearchControlleren su controlador con UISearchBarcomo su tableHeaderView, ajustar la altura de la primera sección como 0 en heightForHeaderInSectionrealidad funciona.

Lo uso self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height);para que la barra de búsqueda esté oculta por defecto.

El resultado es que no hay encabezado para la primera sección, y al desplazarse hacia abajo, se mostrará la barra de búsqueda justo encima de la primera fila.

Raesu
fuente
0

lo más fácil con diferencia es regresar nil, o ""entrar func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?en una sección en la que no desea mostrar el encabezado.

Vilém Kurz
fuente
0

Versión Swift: Swift 5.1 En su
mayoría, puede establecer la altura en el delegado de tableView de esta manera:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
   return UIView(frame: CGRect(x: 0, y: 0, width: view.width, height: CGFloat.leastNormalMagnitude))
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
   return CGFloat.leastNormalMagnitude
}

A veces, cuando creó UITableView con Xib o Storyboard, la respuesta de up no funciona. puedes probar la segunda solución:

let headerView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))
self.tableView.tableHeaderView = headerView

¡Espero que funcione para ti!

Mistdon
fuente