uitableview - Como implementar cabeçalhos e rodapés de seção de exibição de tabela personalizada com Storyboard




tableview header (10)

  1. Adicionar célula no reuseidentified e definir reuseidentified

  2. Código

    class TP_TaskViewTableViewSectionHeader: UITableViewCell{
    }
    

    e

  3. Usar:

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let header = tableView.dequeueReusableCell(withIdentifier: "header", for: IndexPath.init(row: 0, section: section))
        return header
    }
    

Sem usar um storyboard, podemos simplesmente arrastar um UIView para a tela, tableView:viewForHeaderInSection -lo e, em seguida, defini-lo nos métodos delegados tableView:viewForHeaderInSection ou tableView:viewForFooterInSection .

Como podemos conseguir isso com um StoryBoard onde não podemos arrastar um UIView para a tela


A solução que encontrei é basicamente a mesma solução usada antes da introdução dos storyboards.

Crie um novo arquivo de classe de interface vazio. Arraste uma UIView para a tela, layout conforme desejado.

Carregue a ponta manualmente, atribua à seção de cabeçalho / rodapé apropriada nos métodos delegados viewForHeaderInSection ou viewForFooterInSection.

Eu esperava que a Apple simplificasse esse cenário com storyboards e continuasse procurando uma solução melhor ou mais simples. Por exemplo, os cabeçalhos e rodapés personalizados da tabela são diretos para serem adicionados.


Basta usar uma célula protótipo como cabeçalho e / ou rodapé da seção.

  • adicione uma célula extra e coloque os elementos desejados nela.
  • defina o identificador para algo específico (no meu caso SectionHeader)
  • implementar o método tableView:viewForHeaderInSection: ou o método tableView:viewForFooterInSection:
  • use [tableView dequeueReusableCellWithIdentifier:] para obter o cabeçalho
  • implementar o método tableView:heightForHeaderInSection:

-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    static NSString *CellIdentifier = @"SectionHeader"; 
    UITableViewCell *headerView = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (headerView == nil){
        [NSException raise:@"headerView == nil.." format:@"No cells with matching CellIdentifier loaded from your storyboard"];
    }
    return headerView;
}  

Edit: Como alterar o título do cabeçalho (pergunta comentada):

  1. Adicione um rótulo à célula do cabeçalho
  2. defina a etiqueta do rótulo para um número específico (por exemplo, 123)
  3. No seu método tableView:viewForHeaderInSection: get o rótulo chamando:
    UILabel *label = (UILabel *)[headerView viewWithTag:123]; 
  1. Agora você pode usar o rótulo para definir um novo título:
    [label setText:@"New Title"];

Eu consegui trabalhar no iOS7 usando um protótipo de célula no storyboard. Eu tenho um botão na minha exibição de cabeçalho de seção personalizada que aciona um segue que é configurado no storyboard.

Comece com a solução da Tieme

Como o pedro.m aponta, o problema é que tocar no cabeçalho da seção faz com que a primeira célula da seção seja selecionada.

Como Paul Von aponta, isso é corrigido retornando o contentView da célula em vez da célula inteira.

No entanto, como aponta Hons, uma pressão longa no cabeçalho da seção mencionada irá travar o aplicativo.

A solução é remover todos os reconhecimentos de gestos do contentView.

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
     static NSString *CellIdentifier = @"SectionHeader";
     UITableViewCell *sectionHeaderView = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

     while (sectionHeaderView.contentView.gestureRecognizers.count) {
         [sectionHeaderView.contentView removeGestureRecognizer:[sectionHeaderView.contentView.gestureRecognizers objectAtIndex:0]];
     }

     return sectionHeaderView.contentView; }

Se você não estiver usando gestos nas visualizações de cabeçalho da seção, esse pequeno hack parece funcionar.


Eu sei que esta pergunta foi para o iOS 5, mas para o benefício dos futuros leitores, note que o iOS 6 eficaz agora podemos usar dequeueReusableHeaderFooterViewWithIdentifier vez de dequeueReusableCellWithIdentifier .

Portanto, em viewDidLoad , chame registerNib:forHeaderFooterViewReuseIdentifier: ou registerClass:forHeaderFooterViewReuseIdentifier: Em seguida, em viewForHeaderInSection , chame tableView:dequeueReusableHeaderFooterViewWithIdentifier: Você não usa um protótipo de célula com essa API (é uma exibição baseada em NIB ou uma exibição programaticamente criada), mas essa é a nova API para cabeçalhos e rodapés em linha de serviço.


Eu tenho tido problemas em um cenário onde o Header nunca foi reutilizado, mesmo fazendo todos os passos apropriados.

Então, como uma dica para todos que querem alcançar a situação de mostrar seções vazias (0 linhas), avise que:

dequeueReusableHeaderFooterViewWithIdentifier não reutilizará o cabeçalho até que você retorne pelo menos uma linha

Espero que ajude


Para acompanhar a sugestão de Damon , aqui está como eu fiz o cabeçalho selecionável como uma linha normal com um indicador de divulgação.

Eu adicionei um Button com subclasse de UIButton (nome da subclasse "ButtonWithArgument") para a célula protótipo do cabeçalho e excluí o texto do título (o texto "Title" em negrito é outro UILabel na célula protótipo)

em seguida, defina o botão para toda a visualização do cabeçalho e inclua um indicador de divulgação com o truque do Avario

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    static NSString *CellIdentifier = @"PersonGroupHeader";
    UITableViewCell *headerView = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if(headerView == nil)
    {
        [NSException raise:@"headerView == nil, PersonGroupTableViewController" format:[NSString stringWithFormat:@"Storyboard does not have prototype cell with identifier %@",CellIdentifier]];
    }

    //  https://.com/a/24044628/3075839
    while(headerView.contentView.gestureRecognizers.count)
    {
        [headerView.contentView removeGestureRecognizer:[headerView.contentView.gestureRecognizers objectAtIndex:0]];
    }


    ButtonWithArgument *button = (ButtonWithArgument *)[headerView viewWithTag:4];
    button.frame = headerView.bounds; // set tap area to entire header view
    button.argument = [[NSNumber alloc] initWithInteger:section]; // from ButtonWithArguments subclass
    [button addTarget:self action:@selector(headerViewTap:) forControlEvents:UIControlEventTouchUpInside];

    // https://.com/a/20821178/3075839
    UITableViewCell *disclosure = [[UITableViewCell alloc] init];
    disclosure.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    disclosure.userInteractionEnabled = NO;
    disclosure.frame = CGRectMake(button.bounds.origin.x + button.bounds.size.width - 20 - 5, // disclosure 20 px wide, right margin 5 px
          (button.bounds.size.height - 20) / 2,
          20,
          20);
    [button addSubview:disclosure];

    // configure header title text

    return headerView.contentView;
}

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

-(void) headerViewTap:(UIGestureRecognizer *)gestureRecognizer;
{
    NSLog(@"header tap");
    NSInteger section = ((NSNumber *)sender.argument).integerValue;
    // do something here
}

ButtonWithArgument.h

#import <UIKit/UIKit.h>

@interface ButtonWithArgument : UIButton
@property (nonatomic, strong) NSObject *argument;
@end

ButtonWithArgument.m

#import "ButtonWithArgument.h"
@implementation ButtonWithArgument
@end

Quando você retornar o contentView da célula, você terá dois problemas:

  1. acidente relacionado a gestos
  2. você não reutiliza o contentView (todas as vezes, na chamada viewForHeaderInSection , você cria uma nova célula)

Solução:

Classe de invólucro para o cabeçalho / rodapé da tabela. É apenas recipiente, herdado de UITableViewHeaderFooterView , que contém o celular dentro

https://github.com/Magnat12/MGTableViewHeaderWrapperView.git

Registrar classe no seu UITableView (por exemplo, em viewDidLoad)

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.tableView registerClass:[MGTableViewHeaderWrapperView class] forHeaderFooterViewReuseIdentifier:@"ProfileEditSectionHeader"];
}

Em seu UITableViewDelegate:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    MGTableViewHeaderWrapperView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"ProfileEditSectionHeader"];

    // init your custom cell
    ProfileEditSectionTitleTableCell *cell = (ProfileEditSectionTitleTableCell * ) view.cell;
    if (!cell) {
        cell = [tableView dequeueReusableCellWithIdentifier:@"ProfileEditSectionTitleTableCell"];
        view.cell = cell;
    }

    // Do something with your cell

    return view;
}

Se você precisar de uma Implementação Swift, siga as instruções na resposta aceita e, em seguida, em seu UITableViewController, implemente os seguintes métodos:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    return tableView.dequeueReusableCell(withIdentifier: "CustomHeader")
}

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

Se você usar storyboards, poderá usar uma célula protótipo na tableview para estruturar sua visualização de cabeçalho. Definir um ID exclusivo e viewForHeaderInSection você pode desenfileirar a célula com esse ID e convertê-lo em um UIView.





uistoryboard