Personnaliser la section d'en-tête UITableView


141

Je souhaite personnaliser l'en- UITableViewtête de chaque section. Jusqu'à présent, j'ai implémenté

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

cette UITabelViewDelegateméthode. Ce que je veux faire, c'est obtenir l'en-tête actuel pour chaque section et simplement l'ajouter en UILabeltant que sous-vue.

Jusqu'à présent, je ne suis pas en mesure d'accomplir cela. Parce que je n'ai rien trouvé pour obtenir l'en-tête de section par défaut. Première question, existe-t-il un moyen d'obtenir l'en-tête de section par défaut ?

Si ce n'est pas possible, je dois créer une vue de conteneur qui est un UIViewmais, cette fois je dois définir la couleur d'arrière-plan par défaut, la couleur de l'ombre, etc. Parce que, si vous regardez attentivement l'en-tête de la section, il est déjà personnalisé.

Comment puis-je obtenir ces valeurs par défaut pour chaque en-tête de section?

Merci à tous.


1
Quel est le problème avec l'utilisation tableView:titleForHeaderInSection:?
borrrden

Il renvoie un NSString, j'ai besoin de définir une police personnalisée, je ne peux pas si j'utilisetableView:titleForHeaderInSection:
limon

Ou vous pouvez utiliser des images pour imiter les en-têtes de section par défaut. teehanlax.com/blog/ios-6-gui-psd-iphone-5
Desdenova

@limon: Comment implémenter l'en-tête de section: stackoverflow.com/a/32261262/1457385
shallowThought

Réponses:


288

Vous pouvez essayer ceci:

 -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 18)];
    /* Create custom view to display section header... */
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, tableView.frame.size.width, 18)];
    [label setFont:[UIFont boldSystemFontOfSize:12]];
     NSString *string =[list objectAtIndex:section];
    /* Section header is in 0th index... */
    [label setText:string];
    [view addSubview:label];
    [view setBackgroundColor:[UIColor colorWithRed:166/255.0 green:177/255.0 blue:186/255.0 alpha:1.0]]; //your background color...
    return view;
}

thats your bg color watever color you want to set you can
Lochana Ragupathy

Voilà le problème, j'ai déjà fait ce que vous avez écrit. Mais, je ne connais pas la couleur d'arrière-plan par défaut de l'en-tête de section, qui est un peu gris. Mais, j'ai besoin que ce soit exactement l'en-tête de section par défaut.
limon

15
hey allez sur utiliser Digital color meter
Lochana Ragupathy

assurez-vous de définir également backgroundColor de UILabel. Je sais que j'étais un peu confus lorsque mes antécédents ne devenaient pas clairs pour moi.
shulmey

3
qu'est-ce que la liste en ligne NSString * string = [list objectAtIndex: section]; n'importe qui peut me dire
Nisha Gupta

45

La réponse sélectionnée en utilisant tableView :viewForHeaderInSection:est correcte.

Juste pour partager une astuce ici.

Si vous utilisez storyboard / xib, vous pouvez créer une autre cellule prototype et l'utiliser pour votre "cellule de section". Le code pour configurer l'en-tête est similaire à la façon dont vous configurez pour les cellules de ligne.

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    static NSString *HeaderCellIdentifier = @"Header";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:HeaderCellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:HeaderCellIdentifier];
    }

    // Configure the cell title etc
    [self configureHeaderCell:cell inSection:section];

    return cell;
}

14
il y a un certain nombre de problèmes avec cette solution. Le premier est le fait que si vous implémentez "tableView (tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool", vous remarquerez que l'en-tête de section se déplacera avec la ligne lorsque vous glissez. Pour éviter cela, vous devez renvoyer cell.contentView à la place. Le plus gros problème est le fait qu'avec cette solution, l'application se bloque lorsque vous appuyez longuement sur l'en-tête de la section. La manière correcte est de créer une pointe qui étend UITableViewHeaderFooterView, de l'enregistrer avec la tableview et de la renvoyer dans cette méthode. Testé sur iOS8
Kachi le

@Kachi La solution n'utilise viewForHeaderInSectionpas canEditRowAtIndexPathcomme vous l'avez mentionné. Je ne vérifie jamais le crash que vous avez dit, mais pourriez-vous nous dire combien une longue pression provoquera un crash?
samwize le

1
ce que je voulais dire, c'est que si vous implémentez cette solution ET implémentez canEditRowAtIndexPath, vous verrez que l'en-tête glissera également avec la ligne supérieure que vous supprimez si vous ne renvoyez pas cell.contentView. Voir ce message SO: stackoverflow.com/questions/26009722/ ... La pression longue provoque un plantage car un message tente d'être envoyé à un objet désalloué. Voir cet article SO: stackoverflow.com/questions/27622290/…
Kachi

1
Veuillez ne jamais l'utiliser UITableViewCellcomme vue d'en-tête. Il vous sera très difficile de déboguer les problèmes visuels - l'en-tête disparaîtra parfois à cause de la façon dont les cellules sont retirées de la file d'attente et vous chercherez pendant des heures pourquoi jusqu'à ce que vous réalisiez qu'il UITableViewCelln'appartient pas à l'en- UITableViewtête.
raven_raven

Utiliser un UITableViewCellcomme en-tête est tout simplement faux.
Alex Zavatone

31

La version rapide de la réponse de Lochana Tejas :

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let view = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 18))
    let label = UILabel(frame: CGRectMake(10, 5, tableView.frame.size.width, 18))
    label.font = UIFont.systemFontOfSize(14)
    label.text = list.objectAtIndex(indexPath.row) as! String
    view.addSubview(label)
    view.backgroundColor = UIColor.grayColor() // Set your background color

    return view
}

1
comment rendre la hauteur de l'étiquette dynamique selon le texte qui se trouve à l'intérieur de la vue?
Pratik Shah

Le overridemot-clé est redondant. De plus, envisagez de réutiliser les vues d'en-tête plutôt que de les recréer.
Vadim Bulavin

17

Si vous utilisez la vue d'en-tête par défaut, vous ne pouvez modifier le texte avec

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

Pour Swift:

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

Si vous souhaitez personnaliser la vue, vous devez en créer une nouvelle vous-même.


10

pourquoi ne pas utiliser UITableViewHeaderFooterView ?


Vous ne pouvez l'utiliser que si vous n'utilisez pas également - (UIView *) tableView: (UITableView *) tableView viewForHeaderInSection: (NSInteger) section.
SAHM

1
Réponse parfaitement valable. En outre, l'utilisation de UITableViewHeaderFooterView bénéficie du recyclage des vues, tout comme les cellules.
Gregzo

6
@dmarsi Je n'ai trouvé aucune preuve qu'ils soient obsolètes.
Fawkes

8

Si headerInSection n'est pas affiché, vous pouvez essayer ceci.

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

Cela renvoie une hauteur pour l'en-tête d'une section donnée.


1
Ça vous dérange d'élaborer votre réponse?
CinCout

La section d'en-tête n'apparaîtra pas sauf si vous spécifiez avec une méthode hook la «hauteur» de l'en-tête de section. UITableView par défaut n'affiche pas les en-têtes si aucune hauteur n'est spécifiée. @CinCout
theprojectabot

6

La version Swift 3 de Lochana et Estemendoza répond:

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

    let view = UIView(frame: CGRect(x:0, y:0, width:tableView.frame.size.width, height:18))
    let label = UILabel(frame: CGRect(x:10, y:5, width:tableView.frame.size.width, height:18))
    label.font = UIFont.systemFont(ofSize: 14)
    label.text = "This is a test";
    view.addSubview(label);
    view.backgroundColor = UIColor.gray;
    return view

}

Sachez également que vous devez ÉGALEMENT mettre en œuvre:

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

5

Essaye ça......

override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) 
{
    // Background view is at index 0, content view at index 1
    if let bgView = view.subviews[0] as? UIView
    {
        // do your stuff
    }

    view.layer.borderColor = UIColor.magentaColor().CGColor
    view.layer.borderWidth = 1
}

5

Les autres réponses permettent de recréer la vue d'en-tête par défaut, mais ne répondent pas réellement à votre question principale:

existe-t-il un moyen d'obtenir l'en-tête de section par défaut?

Il existe un moyen - implémentez simplement tableView:willDisplayHeaderView:forSection:dans votre délégué. La vue d'en-tête par défaut sera transmise au deuxième paramètre, et à partir de là, vous pouvez la UITableViewHeaderFooterViewconvertir en une , puis ajouter / modifier des sous-vues comme vous le souhaitez.

Obj-C

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    UITableViewHeaderFooterView *headerView = (UITableViewHeaderFooterView *)view;

    // Do whatever with the header view... e.g.
    // headerView.textLabel.textColor = [UIColor whiteColor]
}

Rapide

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
{
    let headerView = view as! UITableViewHeaderFooterView

    // Do whatever with the header view... e.g.
    // headerView.textLabel?.textColor = UIColor.white
}

Vous n'avez pas besoin de le lancer. Vous pouvez simplement ajouter ce que vous voulez à la vue. En fait, créer un nouvel objet ne fera rien à moins que vous ne l’assigniez view.
Alex Zavatone

@AlexZavatone C'est vrai, vous n'avez pas besoin de le diffuser si vous ajoutez simplement des vues. C'est utile si vous souhaitez personnaliser certaines des vues par défaut comme l'étiquette de texte.
Craig Brown

4
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    //put your values, this is part of my code
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 30.0f)];
    [view setBackgroundColor:[UIColor redColor]];
    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(20, 5, 150, 20)];
    [lbl setFont:[UIFont systemFontOfSize:18]];
    [lbl setTextColor:[UIColor blueColor]];
    [view addSubview:lbl];

    [lbl setText:[NSString stringWithFormat:@"Section: %ld",(long)section]];

    return view;
}

4

C'est la solution la plus simple possible. Le code suivant peut être utilisé directement pour créer un en-tête de section personnalisé.

 -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    SectionHeaderTableViewCell *headerView = [tableView dequeueReusableCellWithIdentifier:@"sectionHeader"];

    //For creating a drop menu of rows from the section
    //==THIS IS JUST AN EXAMPLE. YOU CAN REMOVE THIS IF-ELSE.==
    if (![self.sectionCollapsedArray[section] boolValue])
    {
        headerView.imageView.image = [UIImage imageNamed:@"up_icon"];
    }
    else
    {
        headerView.imageView.image = [UIImage imageNamed:@"drop_icon"];
    }

    //For button action inside the custom cell
    headerView.dropButton.tag = section;
    [headerView.dropButton addTarget:self action:@selector(sectionTapped:) forControlEvents:UIControlEventTouchUpInside];

    //For removing long touch gestures.
    for (UIGestureRecognizer *recognizer in headerView.contentView.gestureRecognizers)
    {
        [headerView.contentView removeGestureRecognizer:recognizer];
        [headerView removeGestureRecognizer:recognizer];
    }

    return headerView.contentView;
}

REMARQUE: SectionHeaderTableViewCell est un UITableViewCell personnalisé créé dans Storyboard.


SectionHeaderTableViewCell - utilisation d'un identifiant non déclaré
Boris Gafurov

@BorisGafurov SectionHeaderTableViewCell est juste un exemple de nom que j'ai donné à mon UITableViewCell, que j'ai créé dans le storyboard.
Anish Kumar

2

Si j'étais vous, je ferais une méthode qui retourne un UIView donné un NSString à contenir. Par exemple

+ (UIView *) sectionViewWithTitle:(NSString *)title;

Dans l'implémentation de cette méthode, créez un UIView, ajoutez-y un UILabel avec les propriétés que vous souhaitez définir et, bien sûr, définissez son titre sur celui donné.


Oui, je peux le faire, mais ma question est de savoir comment puis-je obtenir l'arrière-plan de l'en-tête de section par défaut, la valeur de l'ombre, le reste est facile à mettre en œuvre.
limon

que voulez-vous dire par fond d'en-tête de section par défaut
Lochana Ragupathy

1
Eh bien, le plus simple serait d'utiliser l'application Digital Color Meter pour obtenir les couleurs souhaitées. Les prendre par code serait difficile, pour autant que je
sache

2

Solution de @ samwize dans Swift (alors votez pour lui!). Génial en utilisant le même mécanisme de recyclage également pour les sections d'en-tête / pied de page:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let settingsHeaderSectionCell:SettingsHeaderSectionCell = self.dequeueReusableCell(withIdentifier: "SettingsHeaderSectionCell") as! SettingsHeaderSectionCell

    return settingsHeaderSectionCell
}

2
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    if([view isKindOfClass:[UITableViewHeaderFooterView class]]){

        UITableViewHeaderFooterView *headerView = view;

        [[headerView textLabel] setTextColor:[UIColor colorWithHexString:@"666666"]];
        [[headerView textLabel] setFont:[UIFont fontWithName:@"fontname" size:10]];
    }
}

Si vous voulez changer la police du textLabel dans votre en-tête de section, vous voulez le faire dans willDisplayHeaderView. Pour définir le texte, vous pouvez le faire dans viewForHeaderInSection ou titleForHeaderInSection. Bonne chance!


2

Exemple 2019 complet à copier et coller

Commencez par définir "Groupé" sur le storyboard: cela doit se produire au moment de l'initialisation, vous ne pouvez pas vraiment le définir plus tard, il est donc plus facile de se souvenir de le faire sur le storyboard:

entrez la description de l'image ici

Prochain,

Doit implémenter heightForHeaderInSection en raison d'un bogue Apple.

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

Il y a toujours un bogue Apple - depuis dix ans maintenant - où il n'affiche tout simplement pas le premier en-tête (c'est-à-dire l'index 0) si vous n'avez pas heightForHeaderInSection appel.

Donc, tableView.sectionHeaderHeight = 70ça ne marche tout simplement pas, c'est cassé .

Définir un cadre ne sert à rien:

Dans viewForHeaderInSection créez simplement un UIView ().

C'est inutile / n'apporte rien si vous UIView (frame ...) car iOS définit simplement la taille de la vue comme déterminé par le tableau.

Donc, la première ligne de viewForHeaderInSectionsera simplement let view = UIView()et c'est la vue que vous retournez.

func tableView(_ tableView: UITableView,
                       viewForHeaderInSection section: Int) -> UIView? {
    let view = UIView()
    
    let l = UILabel()
    view.addSubview(l)
    l.bindEdgesToSuperview()
    l.backgroundColor = .systemOrange
    l.font = UIFont.systemFont(ofSize: 15)
    l.textColor = .yourClientsFavoriteColor
    
    switch section {
    case 0:
        l.text =  "First section on screen"
    case 1:
        l.text =  "Here's the second section"
    default:
        l.text =  ""
    }
    
    return view
}

Voilà - tout le reste est une perte de temps.

Un autre problème Apple "pointilleux".


L'extension de commodité utilisée ci-dessus est:

extension UIView {
    
    // incredibly useful:
    
    func bindEdgesToSuperview() {
        
        guard let s = superview else {
            preconditionFailure("`superview` nil in bindEdgesToSuperview")
        }
        
        translatesAutoresizingMaskIntoConstraints = false
        leadingAnchor.constraint(equalTo: s.leadingAnchor).isActive = true
        trailingAnchor.constraint(equalTo: s.trailingAnchor).isActive = true
        topAnchor.constraint(equalTo: s.topAnchor).isActive = true
        bottomAnchor.constraint(equalTo: s.bottomAnchor).isActive = true
    }
}

1

Ajoutez comme par magie un en-tête de vue de tableau dans Swift

Récemment, j'ai essayé cela.

J'avais besoin d'un et un seul en-tête dans tout UITableView.

Comme je voulais une UIImageView en haut de la TableView. J'ai donc ajouté un UIImageView au-dessus de UITableViewCell et il a été automatiquement ajouté en tant que tableViewHeader. Maintenant, je connecte ImageView au ViewController et j'ai ajouté l'image.

J'étais confus parce que j'ai fait quelque chose comme ça pour la première fois. Donc, pour effacer ma confusion, ouvrez le format xml du MainStoryBoard et constatez que la vue Image a été ajoutée en tant qu'en-tête.

Cela a fonctionné pour moi. Merci xCode et rapide.



1

swif 4.2

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

    header.textLabel?.textAlignment = .center // for all sections

    switch section {
    case 1:  //only section No.1
        header.textLabel?.textColor = .black
    case 3:  //only section No.3
        header.textLabel?.textColor = .red
    default: //
        header.textLabel?.textColor = .yellow
    }
}


0

Si vous souhaitez simplement ajouter un titre à l'en-tête tableView, n'ajoutez pas de vue. Dans swift 3.x, le code ressemble à ceci:

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    var lblStr = ""
    if section == 0 {
        lblStr = "Some String 1"
    }
    else if section == 1{
        lblStr = "Some String 2"
    }
    else{
        lblStr = "Some String 3"
    }
    return lblStr
}

Vous pouvez implémenter un tableau pour récupérer le titre des en-têtes.


0

Pour revenir à la question d'origine (4 ans plus tard), plutôt que de reconstruire votre propre en-tête de section, iOS peut simplement vous appeler (avec willDisplayHeaderView: forSection :) juste après avoir construit celui par défaut. Par exemple, je voulais ajouter un bouton graphique sur le bord droit de l'en-tête de section:

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
    UITableViewHeaderFooterView * header = (UITableViewHeaderFooterView *) view;
    if (header.contentView.subviews.count >  0) return; //in case of reuse
    CGFloat rightEdge = CGRectGetMaxX(header.contentView.bounds);
    UIButton * button = [[UIButton alloc] initWithFrame:CGRectMake(rightEdge - 44, 0, 44, CGRectGetMaxY(header.contentView.bounds))];
    [button setBackgroundImage:[UIImage imageNamed:@"graphIcon"] forState:UIControlStateNormal];
    [button addTarget:self action:@selector(graphButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
    [view addSubview:button];
}

0

Permet tableView: willDisplayHeaderView:de personnaliser la vue lorsqu'elle est sur le point d'être affichée.

Cela vous donne l'avantage de pouvoir prendre la vue déjà créée pour la vue d'en-tête et de l'étendre, au lieu d'avoir à recréer vous-même la vue d'en-tête entière.

Voici un exemple qui colore la section d'en-tête en fonction d'un BOOL et ajoute un élément de texte de détail à l'en-tête.

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
//    view.tintColor = [UIColor colorWithWhite:0.825 alpha:1.0]; // gray
//    view.tintColor = [UIColor colorWithRed:0.825 green:0.725 blue:0.725 alpha:1.0]; // reddish
//    view.tintColor = [UIColor colorWithRed:0.925 green:0.725 blue:0.725 alpha:1.0]; // pink

    // Conditionally tint the header view
    BOOL isMyThingOnOrOff = [self isMyThingOnOrOff];

    if (isMyThingOnOrOff) {
        view.tintColor = [UIColor colorWithRed:0.725 green:0.925 blue:0.725 alpha:1.0];
    } else {
        view.tintColor = [UIColor colorWithRed:0.925 green:0.725 blue:0.725 alpha:1.0];
    }

    /* Add a detail text label (which has its own view to the section header… */
    CGFloat xOrigin = 100; // arbitrary
    CGFloat hInset = 20;
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(xOrigin + hInset, 5, tableView.frame.size.width - xOrigin - (hInset * 2), 22)];

    label.textAlignment = NSTextAlignmentRight;

    [label setFont:[UIFont fontWithName:@"Helvetica-Bold" size:14.0]
    label.text = @"Hi.  I'm the detail text";

    [view addSubview:label];
}

0

Swift 4.2

Dans Swift 4.2, le nom de la table est un peu changé.

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 18))
        let label = UILabel(frame: CGRect(x: 10, y: 5, width: tableView.frame.size.width, height: 18))
        label.font = UIFont.systemFont(ofSize: 14)
        label.text = list.objectAtIndex(section) as! String
        view.addSubview(label)
        view.backgroundColor = UIColor.gray // Set your background color

        return view
    }
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.