Como ocultar o cabeçalho da primeira seção em UITableView (estilo agrupado)

108

Como o design das visualizações de tabela usando o estilo agrupado mudou consideravelmente com o iOS 7, gostaria de ocultar (ou remover) o primeiro cabeçalho da seção. Até agora não consegui.

Um pouco simplificado, meu código fica assim:

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

Se eu retornar uma altura de 0, os outros dois métodos nunca serão chamados com o índice de seção 0. Mesmo assim, um cabeçalho de seção vazio ainda é desenhado com a altura padrão. (No iOS 6, os dois métodos são chamados. No entanto, o resultado visível é o mesmo.)

Se eu retornar um valor diferente, o cabeçalho da seção obtém a altura especificada.

Se eu retornar 0,01, é quase correto. No entanto, quando eu ligo "Color Misaligned Images" no simulador, ele marca todas as células de visualização da tabela (o que parece ser uma consequência lógica).

As respostas à pergunta UITableView: ocultar o cabeçalho da seção vazia parecem indicar que algumas pessoas tiveram sucesso em ocultar o cabeçalho da seção. Mas pode se aplicar ao estilo simples (em vez do agrupado).

O melhor compromisso até agora é retornar a altura 0,5, resultando em uma linha um pouco mais grossa abaixo da barra de navegação. No entanto, agradeceria se alguém souber como o cabeçalho da primeira seção pode ser completamente oculto.

Atualizar

De acordo com a análise de caglar ( https://stackoverflow.com/a/19056823/413337 ), o problema só surge se a visualização da tabela estiver contida em um controlador de navegação.

Codo
fonte
Eu não entendi essa parte => if (seção == 0) return view; return nil; ou seja, retornar uma visualização quando for a primeira seção e nulo caso contrário?
Zen
A ideia é retornar uma visualização com altura 0 para a primeira seção e retornar nulo para todas as outras seções, de modo que a visualização de tabela use a visualização de cabeçalho padrão para elas. A parte nula funciona bem; a visualização de tabela mostra um cabeçalho para essas seções. Mas a parte da seção 0 é irrelevante porque o método nunca é chamado com section == 0.
Codo
1
Esta resposta parece ser curta e doce. stackoverflow.com/a/23955420/3965
Sr. Rogers,

Respostas:

154

Tenho uma solução alternativa que me parece razoavelmente limpa. Portanto, estou respondendo à minha própria pergunta.

Visto que 0 como a altura do cabeçalho da primeira seção não funciona, eu retorno 1. Em seguida, uso o contentInset para ocultar essa altura abaixo da barra de navegação.

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

Rápido:

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
fonte
6
Usar uma altura de cabeçalho de 0.1f é ainda melhor para escondê-lo.
Chuck Krutsinger
4
Tentei usar 0.1f. Mas o resultado é que os desenhos não estão mais alinhados aos pixels, causando manchas e reduzindo o desempenho. Experimente no simulador: tem a opção de destacar o alinhamento problemático.
Codo
31
Na verdade, uma implementação melhor (com menos probabilidade de falhar no futuro) é usar em CGFLOAT_MINvez de um valor embutido em código. Em outras palavras, não faça return 1.0fou 0.1f, em vez disso, return CGFLOAT_MINse a Apple alguma vez alterar o valor mínimo aceitável, você terá o código a ser alterado se codificar o valor de retorno. Além disso, você ainda não sabe se está usando o menor valor possível. Usando a constante definida, você tem a garantia de usar o menor valor possível e seu código sobreviverá às alterações do sistema operacional.
Chris Ostmo
11
@Chris: Receio que você não tenha entendido. Eu não retorno um valor muito pequeno, mas um múltiplo do tamanho de um pixel para que o desenho permaneça alinhado com os pixels (para bom desempenho e nitidez). Eu então compenso usando a inserção de conteúdo. É improvável que isso mude no futuro, pois é uma distância considerável e visível e não é algo que o sistema operacional possa ignorar.
Codo
8
+1 Por não usar valores de pixel fracionários como deslocamentos da IU.
Ricardo Sanchez-Saez
52

Esta é a forma de ocultar o cabeçalho da primeira seção em UITableView (estilo agrupado).

Solução Swift 3.0 e Xcode 8.0

  1. O delegado do TableView deve implementar o método heightForHeaderInSection

  2. Dentro do método heightForHeaderInSection, retorne o número menos positivo. (não zero!)

    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
fonte
6
retornar CGFloat.leastNonzeroMagnitude em vez de 0 me ajudou. Obrigado!
anoo_radha de
Resposta perfeita, obrigado
Pierre
A propósito, CGFLOAT_MINfor objc é idêntico a CGFloat.leastNonzeroMagnitudeem Swift
DawnSong de
36

A resposta foi muito engraçada para mim e para minha equipe, e funcionou perfeitamente

  • No Interface Builder, basta mover a visualização da mesa sob outra visualização na hierarquia de visualizações.

RAZÃO:

Observamos que isso acontece apenas para a Primeira Visualização na Hierarquia de Visualização, se esta primeira visualização for uma UITableView . Portanto, todos os outros UITableViews semelhantes não têm essa seção chata, exceto a primeira. Tentamos remover o UITableView do primeiro lugar na hierarquia de visualizações e tudo estava funcionando conforme o esperado.

Giorgos Ath
fonte
1
Você ainda tem o efeito de vidro fosco da barra de navegação quando rola a exibição da tabela?
Codo
Você terá esse efeito de desfoque quando configurar sua tableView de acordo. Você precisaria definir o contentInsetpara, por exemplo, {0, 64, 0, 0}para ter o deslocamento de 64px do topo (barra de status mais barra de navegação). O the tableView precisa ser anexado ao topo da tela, não o topLayoutGuide (para deixá-lo alcançar sob a barra de navegação)
Julian F. Weinert
Se você não estiver usando pull para atualizar, isso pareceria bom.
Michael
2
Uau. Isso funcionou para mim no iOS 9 e simplesmente me surpreendeu.
alocar em
Esta deve ser a resposta aceita. Um bug tão estranho!
Oded Harth
25

Use este truque para o tipo agrupado tableView

Copie e cole o código abaixo para sua visualização de tabela no método viewDidLoad :

tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, tableView.bounds.size.width, 0.01f)];
Nitesh Borad
fonte
Ainda não tentei, mas suspeito que essa solução tenha a mesma desvantagem de algumas das outras soluções propostas: os desenhos não são mais alinhados aos pixels, causando manchas e reduzindo o desempenho. O simulador pode revelá-lo: ele tem uma opção para destacar o alinhamento problemático. No entanto, se arredondar para 0, é uma boa solução.
Codo
Sim, acho que arredondou para zero. Porque usei muitas vezes, mas não encontrei nenhum desfoque nos desenhos.
Nitesh Borad
TableHeaderView e visualização Section Header? qual é a diferença,
AsifHabib de
Ou ligeiramente mais curto: _tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 1)].
mojuba
@AsifHabib: tableHeaderView é colocado no topo de todos os elementos da tabela. É a visualização do cabeçalho da própria tabela. E a vista do cabeçalho da seção é a vista a ser colocada em cada seção. Pode haver muitas visualizações do cabeçalho da seção de acordo com o número especificado de seções na tabela. Porém, haverá apenas uma visualização do cabeçalho da tabela.
Nitesh Borad
21

desta forma 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
fonte
2
Esta é uma boa variação da minha solução, exceto que usa valores fracionários. Dessa forma, o texto e as imagens não ficam mais alinhados aos pixels, o desenho fica mais lento e o resultado pode ficar borrado. O simulador possui a opção "Colorir imagens desalinhadas" para revelar este problema.
Codo
Funciona bem para pessoas como eu usando células estáticas com um containerView
thibaut noah
3
Swift 3> 'CGFloat.min' foi renomeado para 'CGFloat.leastNormalMagnitude'
rjobidon
6

Acabei de copiar seu código e tentei. Funciona normalmente (experimentado no simulador). Anexei a visualização do resultado. Você quer essa visão, certo? Ou eu entendi mal o seu problema?

insira a descrição da imagem aqui

caglar
fonte
1
Sim, é basicamente o que eu quero, exceto que minha visualização de tabela está em um controlador de navegação. Isso poderia fazer a diferença?
Codo
2
Eu adicionei tableView ao controlador de navegação e sua situação aparece :) Eu acho que no iOS 7, essa altura do cabeçalho corrige por padrão na visualização de tabela de estilo agrupado. Ao alterar o quadro de tableView, a primeira visualização do cabeçalho pode ser ocultada (como conjunto x = 0 y = -40). No entanto, sei que essa solução não é uma boa solução.
caglar
1
Muito obrigado pelo seu trabalho. Portanto, parece que o problema só surge se a visualização da tabela usa o estilo agrupado e está contida em um controlador de navegação.
Codo
Tentando mudar de viewcontroller para tableviewcontroller, não consegui corrigir o problema com o cabeçalho. Talvez eu esteja faltando alguma coisa ao tentar convertê-lo. (iOS 7.0.3 sim)
Evgeni Petrov
1
Este problema também aparece neste instantâneo! a 0ª célula não está começando de x: 0.0f e y: 0.0f.
Burhanuddin Sunelwala
6

Swift3: heightForHeaderInSection funciona com 0, você só precisa ter certeza de que o cabeçalho está definido como clipsToBounds.

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

se você não definir clipsToBounds, o cabeçalho oculto ficará visível durante a rolagem.

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

    header.clipsToBounds = true
}
h.martin
fonte
1
clipsToBound = true é muito importante se você planeja ocultar completamente a visualização do cabeçalho da seção. Definir sua altura para 0 / CGFLOAT_MIN não é suficiente.
Altimac,
5

Atualização [19/09/17]: A resposta antiga não funciona mais para mim no iOS 11. Obrigado, Apple. O seguinte fez:

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

Resposta Anterior:

Conforme postado nos comentários de Chris Ostomo, o seguinte funcionou para mim:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return CGFLOAT_MIN; // to get rid of empty section header
}
Manindra Moharana
fonte
Suspeito que o conteúdo da visualização da tabela não está mais alinhado aos pixels, causando borrões e reduzindo o desempenho. O simulador pode revelá-lo: ele tem uma opção para destacar o alinhamento problemático. No entanto, se arredondar para 0, é uma boa solução.
Codo
Não, não notei nenhum problema de conteúdo. As restrições pareciam boas.
Manindra Moharana de
1
Bem-vindo! Não funciona mais no iOS 11! Minha correção durou menos de uma semana .. 😞
Manindra Moharana
4

Aqui está como se livrar do cabeçalho da seção superior em um UITableView agrupado, em Swift:

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

No Swift 4.2 e em muitas versões anteriores, em vez de definir a altura do primeiro cabeçalho como 0, como nas outras respostas, você pode apenas definir os outros cabeçalhos como nil. Digamos que você tenha duas seções e só queira que a segunda (ou seja, 1) tenha um cabeçalho. Esse cabeçalho terá o texto Foobar :

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

Tente isto se quiser remover todo o cabeçalho da seção completamente

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

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return CGFloat.leastNormalMagnitude
}
Avinash
fonte
Isso é tudo que preciso. Uma solução simples e fácil. 1+
iGhost
0

Não posso comentar ainda, mas pensei em acrescentar que, se você tiver um UISearchControllerno seu controlador com UISearchBarcomo seu tableHeaderView, definir a altura da primeira seção como 0 dentro heightForHeaderInSectionrealmente funciona.

Eu uso self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height);para que a barra de pesquisa fique oculta por padrão.

O resultado é que não há cabeçalho para a primeira seção e rolar para baixo exibirá a barra de pesquisa logo acima da primeira linha.

Raesu
fonte
0

De longe, o mais fácil é retornar nilou ""entrar func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?em uma seção onde você não deseja exibir o cabeçalho.

Vilém Kurz
fonte
0

Versão Swift: Swift 5.1
Geralmente, você pode definir a altura no delegado tableView assim:

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
}

Às vezes, quando você cria UITableView com Xib ou Storyboard, a resposta de up não funciona. você pode tentar a segunda solução:

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

Espero que funcione para você!

Mistdon
fonte