Comment masquer le premier en-tête de section dans UITableView (style groupé)

108

Comme la conception des vues de tableau utilisant le style groupé a considérablement changé avec iOS 7, je voudrais masquer (ou supprimer) le premier en-tête de section. Jusqu'à présent, je n'ai pas réussi à y parvenir.

Un peu simplifié, mon code ressemble à ceci:

- (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 je renvoie une hauteur de 0, les deux autres méthodes ne seront jamais appelées avec l'index de section 0. Pourtant, un en-tête de section vide est toujours dessiné avec la hauteur par défaut. (Dans iOS 6, les deux méthodes sont appelées. Cependant, le résultat visible est le même.)

Si je renvoie une valeur différente, l'en-tête de section obtient la hauteur spécifiée.

Si je renvoie 0,01, c'est presque correct. Cependant, lorsque j'active "Couleur des images mal alignées" dans le simulateur, cela marque toutes les cellules de la vue tableau (ce qui semble être une conséquence logique).

Les réponses à la question UITableView: masquer l'en-tête de la section vide semblent indiquer que certaines personnes ont réussi à masquer l'en-tête de la section. Mais cela peut s'appliquer au style simple (au lieu du style groupé).

Le meilleur compromis jusqu'à présent est de renvoyer la hauteur 0,5, ce qui donne une ligne un peu plus épaisse sous la barre de navigation. Cependant, j'apprécierais que quelqu'un sache comment le premier en-tête de section peut être complètement caché.

Mettre à jour

Selon l' analyse de caglar ( https://stackoverflow.com/a/19056823/413337 ), le problème ne survient que si la vue de table est contenue dans un contrôleur de navigation.

Codo
la source
Je n'ai pas obtenu cette partie => if (section == 0) return view; retour nul; c'est-à-dire renvoyer une vue quand c'est la première section et nulle sinon?
Zen
L'idée est de renvoyer une vue avec une hauteur de 0 pour la première section et de renvoyer nil pour toutes les autres sections afin que la vue de table utilise la vue d'en-tête par défaut pour elles. La partie nulle fonctionne bien; la vue de table montre un en-tête pour ces sections. Mais la partie de la section 0 n'est pas pertinente car la méthode n'est jamais appelée avec section == 0.
Codo du
1
Cette réponse semble courte et douce. stackoverflow.com/a/23955420/3965
Mr Rogers

Réponses:

154

J'ai une solution de contournement qui me semble raisonnablement propre. Alors je réponds à ma propre question.

Puisque 0 comme hauteur de l'en-tête de la première section ne fonctionne pas, je retourne 1. Ensuite, j'utilise le contentInset pour masquer cette hauteur sous la barre de navigation.

Objectif c:

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

Rapide:

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
la source
6
Utiliser une hauteur d'en-tête de 0,1f est encore mieux pour le cacher.
Chuck Krutsinger
4
J'ai essayé d'utiliser 0.1f. Mais le résultat est que les dessins ne sont plus alignés sur les pixels, ce qui provoque des flous et réduit les performances. Essayez-le simplement dans le simulateur: il a une option pour mettre en évidence l'alignement problématique.
Codo
31
En fait, une meilleure implémentation (moins susceptible de se rompre à l'avenir) consiste à utiliser CGFLOAT_MINau lieu d'une valeur codée en dur. En d'autres termes, ne le faites pas return 1.0fou à la 0.1fplace, return CGFLOAT_MINsi Apple change un jour la valeur minimale acceptable, vous aurez du code à changer si vous codez en dur la valeur de retour. De plus, vous ne savez déjà pas si vous utilisez la plus petite valeur possible. En utilisant la constante définie, vous êtes assuré d'utiliser la plus petite valeur possible et votre code survivra aux modifications du système d'exploitation.
Chris Ostmo
11
@Chris: J'ai bien peur que vous n'ayez pas compris l'idée. Je ne renvoie pas une très petite valeur mais un multiple de la taille d'un pixel pour que le dessin reste aligné sur les pixels (pour de bonnes performances et une netteté). Je le compense ensuite en utilisant l'encart de contenu. Il est peu probable que cela change à l'avenir car il s'agit d'une distance considérable et visible et non pas quelque chose que le système d'exploitation pourrait ignorer.
Codo
8
+1 Pour ne pas utiliser de valeurs de pixel fractionnaires comme décalages d'interface utilisateur.
Ricardo Sanchez-Saez
52

Voici comment masquer le premier en-tête de section dans UITableView (style groupé).

Solution Swift 3.0 et Xcode 8.0

  1. Le délégué de TableView doit implémenter la méthode heightForHeaderInSection

  2. Dans la méthode heightForHeaderInSection, renvoie le nombre le moins positif. (pas zéro!)

    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
    }
user3378170
la source
6
retourner CGFloat.leastNonzeroMagnitude au lieu de 0 m'a aidé. Merci!
anoo_radha
Réponse parfaite, merci
Pierre
À propos, CGFLOAT_MINpour objc est identique à CGFloat.leastNonzeroMagnitudedans Swift
DawnSong
36

La réponse était très drôle pour moi et mon équipe et a fonctionné comme un charme

  • Dans le générateur d'interface, déplacez simplement la vue de table sous une autre vue dans la hiérarchie des vues.

RAISON:

Nous avons observé que cela se produit uniquement pour la première vue dans la hiérarchie des vues, si cette première vue est un UITableView . Donc, tous les autres UITableViews similaires n'ont pas cette section ennuyeuse, sauf la première. Nous avons essayé de déplacer UITableView de la première place dans la hiérarchie des vues, et tout fonctionnait comme prévu.

Giorgos Ath
la source
1
Avez-vous toujours l'effet de verre dépoli de la barre de navigation lorsque vous faites défiler la vue du tableau?
Codo du
Vous aurez cet effet de flou lorsque vous configurerez votre tableView en conséquence. Vous devrez contentInsetpar exemple définir le sur pour {0, 64, 0, 0}avoir le décalage de 64 pixels par rapport au haut (barre d'état plus barre de navigation). Le tableView doit être attaché en haut de l'écran, pas le topLayoutGuide (pour le laisser atteindre sous la barre de navigation)
Julian F. Weinert
Si vous n'utilisez pas pull pour actualiser, cela semble parfait.
Michael
2
Sensationnel. Cela a fonctionné pour moi dans iOS 9 et m'a époustouflé.
allouer
Cela devrait être la réponse acceptée. Un bug tellement étrange!
Oded Harth
25

Utilisez cette astuce pour la table de type groupé

Copiez-collez le code ci-dessous pour votre vue de table dans la méthode viewDidLoad :

tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, tableView.bounds.size.width, 0.01f)];
Nitesh Borad
la source
Je ne l'ai pas essayé mais je soupçonne que cette solution présente le même inconvénient que certaines des autres solutions proposées: les dessins ne sont plus alignés sur les pixels, ce qui provoque des flous et réduit les performances. Le simulateur peut le révéler: il dispose d'une option pour mettre en évidence l'alignement problématique. Cependant, s'il arrondit à 0, alors c'est une bonne solution.
Codo
Oui, je suppose qu'il est arrondi à 0. Parce que je l'ai utilisé plusieurs fois, mais je n'ai trouvé aucun flou dans les dessins.
Nitesh Borad
TableHeaderView et vue d'en-tête de section? quelle est la différence,
AsifHabib
Ou légèrement plus courte: _tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 1)].
mojuba
@AsifHabib: tableHeaderView est placé en haut de tous les éléments du tableau. C'est la vue d'en-tête de la table elle-même. Et la vue d'en-tête de section est une vue à placer sur chaque section. Il peut y avoir de nombreuses vues d'en-tête de section selon le nombre spécifié de sections dans le tableau. Mais, il n'y aura qu'une seule vue d'en-tête de table.
Nitesh Borad
21

cette façon est OK.

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
la source
2
C'est une belle variation de ma solution sauf qu'elle utilise des valeurs fractionnaires. De cette façon, le texte et les images ne sont plus alignés sur les pixels, le dessin est ralenti et le résultat peut devenir flou. Le simulateur dispose de l'option "Couleur des images mal alignées" pour révéler ce problème.
Codo
Fonctionne très bien pour les gens comme moi utilisant des cellules statiques avec un containerView
thibaut noah
3
Swift 3> 'CGFloat.min' a été renommé en 'CGFloat.leastNormalMagnitude'
rjobidon
6

J'ai juste copié votre code et essayé. Il fonctionne normalement (essayé en simulateur). J'ai joint la vue des résultats. Vous voulez une telle vue, non? Ou j'ai mal compris votre problème?

entrez la description de l'image ici

caglar
la source
1
Oui, c'est essentiellement ce que je veux, sauf que ma vue de table est dans un contrôleur de navigation. Cela pourrait-il faire la différence?
Codo du
2
J'ai ajouté tableView au contrôleur de navigation et votre situation apparaît :) Je pense que dans iOS 7, cette hauteur d'en-tête corrige par défaut dans la vue de tableau de style groupé. En changeant le cadre de tableView, la première vue d'en-tête peut être masquée (comme set x = 0 y = -40). Cependant, je sais que cette solution n'est pas une bonne solution.
caglar le
1
Merci beaucoup pour votre travail. Il semble donc que le problème ne se pose que si la vue de table utilise le style groupé et est contenue dans un contrôleur de navigation.
Codo du
En essayant de passer de viewcontroller à tableviewcontroller, je n'ai pas pu résoudre le problème avec l'en-tête. Il me manque peut-être quelque chose en essayant de le convertir. (iOS 7.0.3 sim)
Evgeni Petrov
1
Ce problème apparaît également dans cet instantané! la 0ème cellule ne part pas de x: 0.0f & y: 0.0f.
Burhanuddin Sunelwala
6

Swift3: heightForHeaderInSection fonctionne avec 0, il vous suffit de vous assurer que l'en-tête est défini sur clipsToBounds.

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

si vous ne définissez pas l'en-tête masqué clipsToBounds, il sera visible lors du défilement.

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

    header.clipsToBounds = true
}
h.martin
la source
1
clipsToBound = true est très important si vous prévoyez de masquer complètement la vue d'en-tête de section. Définir sa hauteur sur 0 / CGFLOAT_MIN ne suffit pas.
Altimac
5

Mise à jour [19/09/17]: l'ancienne réponse ne fonctionne plus pour moi dans iOS 11. Merci Apple. Ce qui suit a fait:

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

Réponse précédente:

Comme indiqué dans les commentaires de Chris Ostomo, ce qui suit a fonctionné pour moi:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return CGFLOAT_MIN; // to get rid of empty section header
}
Manindra Moharana
la source
Je soupçonne que le contenu de votre vue de tableau n'est plus aligné sur les pixels, ce qui provoque des flous et réduit les performances. Le simulateur peut le révéler: il dispose d'une option pour mettre en évidence l'alignement problématique. Cependant, s'il arrondit à 0, alors c'est une bonne solution.
Codo le
Non, je n'ai remarqué aucun problème de contenu. Les contraintes semblaient bien.
Manindra Moharana du
1
Welp! Ne fonctionne plus sous iOS 11! Mon correctif a duré moins d'une semaine .. 😞
Manindra Moharana
4

Voici comment se débarrasser de l'en-tête de section supérieur dans un UITableView groupé, dans Swift:

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

Dans Swift 4.2 et de nombreuses versions antérieures, au lieu de définir la hauteur du premier en-tête à 0 comme dans les autres réponses, vous pouvez simplement définir les autres en-têtes sur nil. Supposons que vous ayez deux sections et que vous ne souhaitiez que la seconde (c'est-à-dire 1) avoir un en-tête. Cet en-tête contiendra le texte Foobar :

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

Essayez ceci si vous souhaitez supprimer complètement tous les en-têtes de section

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

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return CGFloat.leastNormalMagnitude
}
Avinash
la source
C'est juste dont j'ai besoin. Une solution simple et facile. 1+
iGhost
0

Je ne peux pas encore commenter mais j'ai pensé ajouter que si vous avez un UISearchControllersur votre contrôleur avec UISearchBarcomme vôtre tableHeaderView, définir la hauteur de la première section sur 0 dans heightForHeaderInSectionfonctionne effectivement.

J'utilise self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height);pour que la barre de recherche soit masquée par défaut.

Le résultat est qu'il n'y a pas d'en-tête pour la première section, et le défilement vers le bas affichera la barre de recherche juste au-dessus de la première ligne.

Raesu
la source
0

le plus simple est de loin de retourner nil, ou ""dans func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?une section où vous ne souhaitez pas afficher l'en-tête.

Vilém Kurz
la source
0

Version Swift: Swift 5.1 La
plupart du temps, vous pouvez définir la hauteur dans le délégué tableView comme ceci:

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
}

Parfois, lorsque vous avez créé UITableView avec Xib ou Storyboard, la réponse de up ne fonctionne pas. vous pouvez essayer la deuxième solution:

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

J'espère que ça marche pour toi!

mistdon
la source