Personalizar seção de cabeçalho UITableView

141

Eu quero personalizar o UITableViewcabeçalho para cada seção. Até agora, eu implementei

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

este UITabelViewDelegatemétodo. O que eu quero fazer é obter o cabeçalho atual para cada seção e apenas adicionar UILabelcomo uma subvisão.

Até agora, não sou capaz de fazer isso. Porque não consegui encontrar nada para obter o cabeçalho da seção padrão. Primeira pergunta, existe alguma maneira de obter o cabeçalho da seção padrão ?

Se não for possível, preciso criar uma exibição de contêiner UIView, mas, desta vez, preciso definir a cor de plano de fundo padrão, a cor da sombra etc. Porque, se você observar atentamente o cabeçalho da seção, ele já estará personalizado.

Como posso obter esses valores padrão para cada cabeçalho de seção?

Obrigado a todos.

limão
fonte
1
O que há de errado em usar tableView:titleForHeaderInSection:?
borrrden
Ele retorna um NSString, eu preciso definir personalizado fonte para que, eu não posso se eu usartableView:titleForHeaderInSection:
limon
Ou você pode usar imagens para imitar os cabeçalhos de seção padrão. teehanlax.com/blog/ios-6-gui-psd-iphone-5
Desdenova
@limon: Como implementar cabeçalho da seção: stackoverflow.com/a/32261262/1457385
shallowThought

Respostas:

288

Você pode tentar isso:

 -(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;
}
Lochana Ragupathy
fonte
isso é o seu bg cor watever você deseja definir que puder
Lochana Ragupathy
Esse é o problema, eu já fiz o que você escreveu. Mas, eu não sei a cor de fundo padrão do cabeçalho da seção, que é meio cinza. Mas, eu preciso que ele seja exatamente o cabeçalho da seção padrão.
limon
15
ei, vamos usar o medidor de cores digital
Lochana Ragupathy
certifique-se de definir também o backgroundColor do UILabel. Eu sei que fiquei um pouco confusa quando meu passado não estava ficando claro para mim.
Shulmey
3
o que é lista na linha NSString * string = [list objectAtIndex: section]; Alguém pode me dizer
Nisha Gupta
45

A resposta selecionada usando tableView :viewForHeaderInSection:está correta.

Apenas para compartilhar uma dica aqui.

Se você estiver usando o storyboard / xib, poderá criar outra célula protótipo e usá-la na sua "célula de seção". O código para configurar o cabeçalho é semelhante ao modo como você configura para células de linha.

- (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;
}
samwize
fonte
14
há várias coisas erradas com esta solução. Primeiro, o fato de que se você implementar "tableView (tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool", você perceberá que o cabeçalho da seção se moverá junto com a linha quando você deslizar. Para evitar isso, você deve retornar cell.contentView. O problema maior é o fato de que, com esta solução, o aplicativo falha quando você pressiona o cabeçalho da seção. A maneira correta é criar uma ponta que estenda o UITableViewHeaderFooterView, registre-a na tableview e retorne-a neste método. Testado no iOS8
Kachi
@Kachi A solução viewForHeaderInSectionnão está usando canEditRowAtIndexPathcomo você mencionou. Nunca verifiquei a falha que você disse, mas você poderia esclarecer como uma pressão prolongada causará uma falha?
samwize 28/09
1
o que eu quis dizer foi que, se você implementar esta solução E implementar canEditRowAtIndexPath, verá que o cabeçalho também deslizará com a linha superior que você está excluindo, se não retornar cell.contentView. Consulte esta publicação do SO: stackoverflow.com/questions/26009722/… A pressão prolongada causa uma falha porque uma mensagem tenta ser enviada para um objeto desalocado. Veja esta postagem do SO: stackoverflow.com/questions/27622290/…
Kachi 29/15
1
Por favor, nunca use UITableViewCellcomo uma visualização de cabeçalho. É muito difícil depurar falhas visuais - o cabeçalho às vezes desaparece por causa de como as células são desenfileiradas e você estará procurando por horas por que isso até que você perceba UITableViewCellque não pertence a eleUITableView cabeçalho.
Raven_raven 28/09
Usar um UITableViewCellcomo cabeçalho está simplesmente errado.
Alex Zavatone 08/11
31

Versão rápida da resposta 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
}
estemendoza
fonte
1
como tornar a altura da etiqueta dinâmica de acordo com o texto que está dentro da visualização?
precisa
A overridepalavra-chave é redundante. Além disso, considere reutilizar as visualizações de cabeçalho em vez de recriá-las.
Vadim Bulavin
17

Se você usar a visualização de cabeçalho padrão, poderá alterar apenas o texto com

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

Para Swift:

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

Se você quiser personalizar a visualização, precisará criar uma nova.

Mert
fonte
10

por que não usar UITableViewHeaderFooterView ?

user836773
fonte
Você só pode usar isso se também não usar - (UIView *) tableView: (UITableView *) tableView viewForHeaderInSection: (NSInteger).
SAHM
1
Resposta perfeitamente válida. Além disso, o uso do UITableViewHeaderFooterView se beneficia da reciclagem da visualização, assim como as células.
Gregzo
6
@dmarsi Eu não encontrei nenhuma evidência deles sendo preteridos.
Fawkes
8

Se headerInSection não for exibido, tente isso.

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

Isso retorna uma altura para o cabeçalho de uma determinada seção.

Kathen
fonte
1
Mente em elaborar sua resposta?
18715 CinCout
A seção do cabeçalho não será exibida, a menos que você especifique com um método o gancho da 'altura' do cabeçalho da seção. O padrão UITableView é não mostrar cabeçalhos se nenhuma altura for especificada. @CinCout
theprojectabot
6

Swift 3 versão de lochana e estemendoza respostas:

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

}

Além disso, saiba que você TAMBÉM precisa implementar:

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

Tente isso ......

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
}
Gigi
fonte
5

As outras respostas fazem um bom trabalho de recriar a exibição de cabeçalho padrão, mas na verdade não respondem à sua pergunta principal:

existe alguma maneira de obter o cabeçalho da seção padrão?

Existe uma maneira - basta implementar tableView:willDisplayHeaderView:forSection:em seu delegado. A visualização padrão do cabeçalho será passada para o segundo parâmetro e, a partir daí, você poderá convertê-la em UITableViewHeaderFooterViewae, em seguida, adicionar / alterar subvisões conforme desejar.

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]
}

Rápido

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
}
Craig Brown
fonte
Você não precisa lançá-lo. Você pode apenas adicionar o que deseja à vista. De fato, a criação de um novo objeto não fará nada, a menos que você o atribua view.
Alex Zavatone 9/11
@AlexZavatone Isso mesmo, você não precisa transmiti-lo se estiver apenas adicionando visualizações. É útil se você deseja personalizar algumas das visualizações padrão, como o rótulo do texto.
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;
}
Boris Nikolic
fonte
4

Esta é a solução mais fácil possível. O código a seguir pode ser usado diretamente para criar um cabeçalho de seção personalizado.

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

NOTA: SectionHeaderTableViewCell é um UITableViewCell personalizado criado no Storyboard.

Anish Kumar
fonte
SectionHeaderTableViewCell - uso de identificador não declarado
Boris Gafurov
@BorisGafurov SectionHeaderTableViewCell é apenas um nome de exemplo que eu dei ao meu UITableViewCell, que criei no storyboard.
Anish Kumar
2

Se eu fosse você, criaria um método que retornaria uma UIView que um NSString contivesse. Por exemplo

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

Na implementação desse método, crie um UIView, adicione um UILabel a ele com as propriedades que você deseja definir e, é claro, defina seu título para o especificado.

cpprulez
fonte
Sim, eu posso fazer isso, mas minha pergunta é como obter o plano de fundo do cabeçalho da seção padrão, o valor da sombra, o resto é fácil de implementar.
limon
o que você quer dizer com fundo padrão cabeçalho da seção
Lochana Ragupathy
1
Bem, o mais fácil seria usar o aplicativo Digital Color Meter para obter as cores desejadas. Levando-os pelo código seria difícil, tanto quanto eu posso dizer ...
cpprulez
2

A solução de @ samwize no Swift (então vote nele!). Brilhante usando o mesmo mecanismo de reciclagem também para seções de cabeçalho / rodapé:

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

    return settingsHeaderSectionCell
}
Javier Calatrava Llavería
fonte
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]];
    }
}

Se você quiser alterar a fonte do textLabel no cabeçalho da seção, faça isso no willDisplayHeaderView. Para definir o texto, você pode fazê-lo em viewForHeaderInSection ou titleForHeaderInSection. Boa sorte!

John Ottenlips
fonte
2

Exemplo completo de 2019 para copiar e colar

Primeiro set "Agrupado" no storyboard: tem que acontecer no momento do init, você não pode configurá-lo mais tarde, por isso é mais fácil lembrar de fazê-lo no storyboard:

insira a descrição da imagem aqui

Próximo,

É necessário implementar heightForHeaderInSection devido a um erro da Apple.

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

Ainda existe um bug da Apple - há dez anos - em que ele simplesmente não mostra o primeiro cabeçalho (ou seja, índice 0) se você não tiver heightForHeaderInSection chamada.

Então, tableView.sectionHeaderHeight = 70simplesmente não funciona, está quebrado .

Definir um quadro não alcança nada:

Em viewForHeaderInSectionsimplesmente criar um UIView ().

Não faz sentido / não consegue nada se você UIView (quadro ...) já que o iOS simplesmente define o tamanho da exibição, conforme determinado pela tabela.

Portanto, a primeira linha de viewForHeaderInSectionserá simples let view = UIView()e essa é a visão que você retorna.

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
}

É isso aí - qualquer outra coisa é uma perda de tempo.

Outra questão "exigente" da Apple.


A extensão de conveniência usada acima é:

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
    }
}
Fattie
fonte
1

Adicione magicamente o cabeçalho do Table View rapidamente

Recentemente eu tentei isso.

Eu precisava de um e apenas um cabeçalho em todo o UITableView.

Como eu queria um UIImageView na parte superior do TableView. Então, adicionei um UIImageView na parte superior do UITableViewCell e ele foi automaticamente adicionado como tableViewHeader. Agora, conecto o ImageView ao ViewController e adiciono a imagem.

Fiquei confuso porque fiz algo assim pela primeira vez. Então, para esclarecer minha confusão, abra o formato xml do MainStoryBoard e localizei o Image View como um cabeçalho.

Funcionou para mim. Obrigado xCode e rápido.

Somir Saikia
fonte
1

chame esse método delegado

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

return @"Some Title";
}

isso permitirá adicionar automaticamente um cabeçalho padrão com título dinâmico.

Você pode usar cabeçalho / rodapé reutilizável e personalizável.

https://github.com/sourov2008/UITableViewCustomHeaderFooterSection

Shourob Datta
fonte
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
    }
}
flowGlen
fonte
0

Se você quiser apenas adicionar um título ao cabeçalho tableView, não adicione uma visualização. No swift 3.x, o código é assim:

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
}

Você pode implementar uma matriz para buscar o título para os cabeçalhos.

abhishek chakrabartti
fonte
0

Voltando à pergunta original (4 anos depois), em vez de reconstruir seu próprio cabeçalho de seção, o iOS pode simplesmente ligar para você (com willDisplayHeaderView: forSection :) logo após criar o padrão. Por exemplo, eu queria adicionar um botão de gráfico na borda direita do cabeçalho da seção:

- (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];
}
Mackworth
fonte
0

Usar tableView: willDisplayHeaderView: para personalizar a exibição quando ela estiver prestes a ser exibida.

Isso oferece a vantagem de poder aproveitar e ampliar a visualização que já foi criada para a visualização do cabeçalho, em vez de ter de recriar a visualização inteira do cabeçalho.

Aqui está um exemplo que colore a seção do cabeçalho com base em um BOOL e inclua um elemento de texto detalhado no cabeçalho.

- (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];
}
Alex Zavatone
fonte
0

Swift 4.2

No Swift 4.2, o nome da tabela é um pouco alterado.

    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
    }
Esmaeil
fonte