UITableView: viewForHeaderInSection: non appelé pendant reloadData:


127

J'ai configuré la tableview avec des liaisons correctes de délégué et de source de données .. la méthode reloadData appelle la source de données et les méthodes de délégué à l'exception de viewForHeaderInSection:.

Pourquoi est-ce si?


30
Est-ce que le heightForHeaderInSection:mis en œuvre?
7usam

Avez-vous défini une valeur pour TableView sectionHeaderHeight?
Carter Medlin

Réponses:


256

L'utilisation de tableView:viewForHeaderInSection:nécessite que vous implémentiez également tableView:heightForHeaderInSection:. Cela devrait renvoyer une hauteur non nulle appropriée pour l'en-tête. Assurez-vous également de ne pas implémenter également le tableView:titleForHeaderInSection:. Vous ne devez utiliser que l'un ou l'autre ( viewForHeaderou titleForHeader).


3
Assurez-vous qu'il n'y a pas de faute de frappe dans la signature de la méthode. Une fausse lettre signifie qu'elle ne sera pas appelée. Vérifiez également le boîtier. Assurez-vous également que vous renvoyez 0 de numberOfSections.
rmaddy

tout est correct et se compile correctement .. le problème que je voulais comprendre concerne le moment auquel la méthode est appelée .. tableView: viewForHeaderInSection est appelée lorsque la table est sur le point d'être affichée et non dans le cadre de l'exécution de la synchronisation de [ tableview reloadData]
inforeqd

@maddy OMG Merci, c'est tellement stupide de ma part que j'ai créé mes instances mais je ne les ai pas ajoutées à mon tableau
Happiehappie

4
Vous pouvez absolument avoir les deux. viewForHeaderInSection: aura priorité sur titleForHeaderInSection: La seule exigence est que vous définissiez estiméSectionHeaderHeight sur votre vue de table avec quelque chose de différent de 0, sinon viewForHeaderInSection: ne sera jamais appelé
romrom

Ajout au commentaire de @ romrom: si vous avez implémenté à la fois titleForHeaderInSection:et viewForHeaderInSection:et que la vue renvoyée par ce dernier est une sous-classe de UITableViewHeaderFooterViewalors elle textLabel.textest automatiquement définie sur la version en majuscules de la titleForHeaderInSection:chaîne. Pour éviter ce problème, n'implémentez pas titleForHeaderInSection:ou n'utilisez pas d' étiquette personnalisée au lieu de celle héritée textLabel.
Ortwin Gentz

40

L'astuce est que ces deux méthodes appartiennent à des UITableViewprotocoles différents : tableView:titleForHeaderInSection:est une UITableViewDataSourceméthode de protocole, où tableView:viewForHeaderInSectionappartient UITableViewDelegate.

Cela signifie:

  • Si vous implémentez les méthodes mais que vous vous assignez uniquement comme dataSourcepour UITableView, votre tableView:viewForHeaderInSectionimplémentation sera ignorée.

  • tableView:viewForHeaderInSectiona une priorité plus élevée. Si vous implémentez les deux méthodes et que vous vous attribuez à la fois le dataSourceet le delegatepour le UITableView, vous retournerez les vues pour les en-têtes de section mais votre tableView:titleForHeaderInSection:sera ignoré.

J'ai également essayé de supprimer tableView:heightForHeaderInSection:; cela fonctionnait bien et ne semblait pas affecter les procédures ci-dessus. Mais la documentation indique qu'il est nécessaire pour que le tableView:viewForHeaderInSectionfonctionne correctement; donc pour être sûr, il est sage de mettre en œuvre ceci aussi.


6
Tu as fait ma journée !!! Oublié d'assigner UITableViewDelegateà self, parce que je pensais, c'est tableView:viewForHeaderInSectionune UITableViewDataSourceméthode. Je vous remercie!
denis631

1
"tableView: viewForHeaderInSection" n'est pas vital. Ce qui est vital, c'est que vous reveniez en quelque sorte une hauteur. Vous pouvez y parvenir par 1. une estimation ou 2. une valeur codée en dur ou 3. une titleForHeaderqui a une taille intrinsèque. La taille intrinsèque est calculée en fonction de la famille de polices et de la taille.
Honey

28

@rmaddy a mal énoncé la règle, deux fois: en réalité, tableView:viewForHeaderInSection:ne nécessite pas que vous implémentiez également tableView:heightForHeaderInSection:, et il est également parfaitement bien d'appeler à la fois titleForHeaderet viewForHeader. Je vais énoncer la règle correctement juste pour mémoire:

La règle est simplement que viewForHeadercela ne sera pas appelé à moins que vous ne donniez une hauteur à l'en-tête. Vous pouvez le faire de trois manières différentes:

  • Mettre en œuvre tableView:heightForHeaderInSection:.

  • Mettez la table sectionHeaderHeight.

  • Appel titleForHeader(cela donne en quelque sorte à l'en-tête une hauteur par défaut s'il n'en a pas autrement).

Si vous ne faites rien de tout cela, vous n'aurez aucun en-tête et viewForHeaderne serez pas appelé. C'est parce que sans hauteur, le runtime ne saura pas redimensionner la vue, donc il ne prend pas la peine d'en demander une.


Dans la documentation pour tableView:viewForHeaderInSection:: "Cette méthode ne fonctionne correctement que lorsqu'elle tableView:heightForHeaderInSection:est également implémentée.".
rmaddy

1
Bien. Ce que disent les documents, ils le disent. Maintenant, expérimentez. Les faits sont comme je l'ai dit.
mat

Et comment pouvez-vous avoir les deux titleForHeaderInSectionet viewForHeaderInSection? La vue tableau n'appellera que l'un des deux (j'oublie ce qui a la priorité pour le moment).
rmaddy

1
En fait, il y a une autre pièce du puzzle, qui est parfois viewForHeader appelée sans aucune de ces trois façons d'attribuer une hauteur. J'ai eu cela se produire, où mon a viewForHeaderété appelé et les en-têtes sont apparus très bien, jusqu'au jour où, sans changement de ma part, ils ne l'ont pas fait . C'est à ce moment-là que j'ai commencé à expérimenter pour découvrir comment viewForHeaders'appeler les exigences minimales . Et maintenant je sais. Et maintenant vous aussi.
mat

2
@texas Non, je ne fais pas de xamarin. Ajouter un autre niveau d'indirection par-dessus les frameworks Cocoa ferait juste exploser ma tête. :)
matt

20

Le don estimatedSectionHeaderHeightet les sectionHeaderHeightvaleurs ont résolu mon problème. par exemple, self.tableView.estimatedSectionHeaderHeight = 100 self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension


Mon problème a commencé après la mise à niveau vers Swift 3.1. Cette solution l'a corrigé.
zevij

@pbuchheit Apple Docs dit qu'il est disponible à partir d'iOS 7.0+, veuillez jeter un œil ici, developer.apple.com/documentation/uikit/uitableview/…
Sharukh Mastan

@Sharukh Mastan On dirait que vous avez raison. Pour une raison quelconque, je recevais un avertissement lorsque j'ai essayé d'utiliser cette propriété, mais il a disparu après avoir fait une construction propre.
pbuchheit

7

En partant de la réponse de rmaddy, j'essayais de masquer la vue d'en-tête et retournais 0,0f pour "tableView: heightForHeaderInSection" et une vue de 0 hauteur à partir de tableView:viewForHeaderInSection.

Après avoir changé de return 1.0fà return 0.0fin tableView:heightForHeaderInSection, la méthode déléguée tableView:viewForHeaderInSectiona en effet été appelée.

Il s'avère que mon effet souhaité fonctionne sans avoir à utiliser "tableView: heightForHeaderInSection"; mais cela peut être utile à d'autres personnes qui rencontrent un problème lors de l'appel de la méthode de délégation "tableView: heightForHeaderInSection".


5

Vous devez mettre en œuvre tableView:heightForHeaderInSection: et définir la hauteur de l'en-tête> 0.

Cette méthode déléguée va de pair avec le viewForHeaderInSection: méthode.

J'espère que ça aide.

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
         return 40;
}

Avez-vous vérifié que votre réponse fonctionne réellement? Parce que si vous lisez attentivement, il est indiqué qu'au départ, viewForHeaderInSection est appelé. Il n'est pas appelé uniquement lorsque la table est rechargée!
Karlis

5

Il convient de noter brièvement que si votre implémentation de tableView:heightForHeaderInSection:retours UITableViewAutomaticDimension, tableView:viewForHeaderInSection:ne sera pas appelée.

UITableViewAutomaticDimensionsuppose qu'une norme UITableViewHeaderFooterViewsera utilisée qui est remplie avec la méthode déléguée tableView:titleForHeaderInSection:.

À partir des commentaires dans le UITableView.h:

Le renvoi de cette valeur à partir de tableView:heightForHeaderInSection:ou tableView:heightForFooterInSection:entraîne une hauteur qui correspond à la valeur renvoyée par tableView:titleForHeaderInSection:ou tableView:titleForFooterInSection:si le titre n'est pas nul.


1
si vous définissez estimatedSectionHeaderHeightune valeur, tableView:viewForHeaderInSectionsera appelée (de la même manière que les dimensions automatiques pour les lignes fonctionnent)
GreatWiz

Intéressant, merci. De retour à 7.1, cette subtilité de la hauteur estimée était importante pour les cellules , ce qui aurait pu être le cas pour les en-têtes aussi - mais ce n'est pas très pertinent maintenant!
Benjohn

3

Je viens d'avoir un problème avec les en-têtes qui ne s'affichent pas pour iOS 7.1 , mais qui fonctionnent bien avec les versions ultérieures que j'ai testées, explicitement avec 8.1 et 8.4.

Pour le même code, 7.1 était pas appel d' une des méthodes de délégués d' en- tête de section à tous, y compris: tableView:heightForHeaderInSection:ettableView:viewForHeaderInSection: .

Après expérimentation, j'ai constaté que la suppression de cette ligne de mes viewDidLoaden-têtes créés réapparaît pour la version 7.1 et n'a pas d'impact sur les autres versions que j'ai testées:

// _Removing_ this line _fixed_ headers on 7.1
self.tableView.estimatedSectionHeaderHeight = 80;

… Donc, il semble y avoir une sorte de conflit là-bas pour 7.1, au moins.


3

Le même problème s'est produit avec moi, mais comme j'utilisais le calcul automatique de la hauteur à partir de xCode 9 , je ne peux pas donner de valeur de hauteur explicite comme mentionné ci-dessus. Après quelques expérimentations, j'ai eu une solution , nous devons remplacer cette méthode car,

-(CGFloat)tableView:(UITableView *)tableView 
         estimatedHeightForHeaderInSection:(NSInteger)section
{
      return 44.0f;
}

Bien que j'ai coché les deux options

  1. Calcul automatique de la hauteur
  2. Calcul automatique de la hauteur estimée

du storyboard comme le dit Apple, mais j'ai quand même cette erreur étrange.

Remarque : cette erreur n'a été affichée que sur la version IOS-10 et non sur la version IOS-11 . C'est peut-être un bogue de xCode. Merci


0

Voici ce que j'ai trouvé ( Swift 4 ) (grâce à ce commentaire sur une autre question)

Que j'utilise titleForHeaderInSection ou viewForHeaderInSection - ce n'est pas qu'ils n'étaient pas appelés lorsque la vue de la table était défilée et que de nouvelles cellules étaient chargées, mais tous les choix de police que j'ai faits pour le textLabel de headerView n'apparaissaient que sur ce qui était initialement visible au chargement , et non comme le tableau défilait.

Le correctif était willDisplayHeaderView:

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    if let header = view as? UITableViewHeaderFooterView {
        header.textLabel?.font = UIFont(name: yourFont, size: 42)
    }
}

0

Dans mon cas, j'ai créé une vue d'en-tête en utilisant UITableviewCellet en renvoyant la cellule viewForHeaderInSectioncomme ceci

return cell

changé cela en

return cell.contentView 

A travaillé pour moi.


0

Dans mon cas

viewForHeaderInSection

a été implémenté dans une classe dérivée très lointaine qui ne gênait pas de passer en superclasse.


0

La raison pour laquelle il viewForHeaderInSectionn'est pas appelé est l'une des deux raisons suivantes:

Soit vous n'avez pas configuré votre UITableViewDelegate, soit vous ne l'avez pas configuré UITableViewDelegatecorrectement.


0

Dans mon cas, c'était parce que je n'ai pas implémenté:

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat

-1

Parfois, le réglage tableview.delegateou datasource = nildans les méthodes viewWillAppear:ou viewDidAppear:peut provoquer ce problème. Assurez-vous de ne pas faire cela ...


-1

J'avais copié et collé les deux méthodes suivantes d'un projet Swift 2 dans mon projet Swift 3 qui n'ont jamais été appelées car dans Swift 3 ces méthodes doivent avoir "-" avant le premier nom de paramètre.

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

func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: B2BTrolleyHeaderFooterView.reuseIdentifier) as! B2BTrolleyHeaderFooterView        
    return headerView
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.