Alterar o comportamento de rolagem padrão do header da seção UITableView

Eu tenho um UITableView com duas seções. É uma visão simples de tabela. Eu estou usando viewForHeaderInSection para criar modos de exibição personalizados para esses headers. Por enquanto, tudo bem.

O comportamento de rolagem padrão é que, quando uma seção é encontrada, o header da seção permanece ancorado abaixo da barra de navegação, até a próxima seção rolar para a exibição.

Minha pergunta é a seguinte: posso alterar o comportamento padrão para que os headers da seção NÃO fiquem ancorados na parte superior, mas, em vez disso, role na barra de navegação com o restante das linhas da seção?

Estou faltando alguma coisa óbvia?

Obrigado.

A maneira como resolvi esse problema é ajustar o contentOffset acordo com o contentInset no UITableViewControllerDelegate (estende o UIScrollViewDelegate ) assim:

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat sectionHeaderHeight = 40; if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) { scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0); } else if (scrollView.contentOffset.y>=sectionHeaderHeight) { scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0); } } 

O único problema aqui é que ele perde um pouco de retorno ao rolar de volta para o topo.


{NOTA: O “40” deve ser a altura exata do header SEU seção 0. Se você usar um número maior do que a altura do header da seção 0, verá que a sensação do dedo é afetada (tente como “1000” e você verá que o comportamento de rejeição é meio estranho no topo). se o número corresponder à sua altura do header da seção 0, a sensação do dedo parece ser perfeita ou quase perfeita.}

Você também pode adicionar uma seção com zero linhas na parte superior e simplesmente usar o rodapé da seção anterior como um header para a próxima.

Se eu estivesse fazendo isso, aproveitaria o fato de que UITableViews no estilo Plain não têm os headers colantes e os do estilo Agrupado. Eu provavelmente tentaria, pelo menos, usar uma célula de tabela personalizada para imitar a aparência de células comuns em uma tabela agrupada.

Eu realmente não tentei isso, então pode não funcionar, mas é o que eu sugiro fazer.

Eu sei que chega tarde, mas eu encontrei a solução definitiva!

O que você quer fazer é ter 10 seções, deixar o dataSource retornar 20. Use números pares para headers de seção e números ímpares para o conteúdo da seção. algo assim

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (section%2 == 0) { return 0; }else { return 5; } } -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { if (section%2 == 0) { return [NSString stringWithFormat:@"%i", section+1]; }else { return nil; } } 

Voilá! : D

Há várias coisas que precisam ser feitas para resolver esse problema de uma maneira não hacky:

  1. Definir o estilo de exibição de tabela para UITableViewStyleGrouped
  2. Definir a vista da tabela backgroundColor para [UIColor clearColor]
  3. Defina o backgroundView em cada célula da vista de tabela para uma vista vazia com backgroundColor [UIColor clearColor]
  4. Se necessário, defina a exibição de tabela rowHeight adequadamente ou substitua tableView:heightForRowAtIndexPath: se linhas individuais tiverem alturas diferentes.

Originalmente publicado Aqui , uma solução rápida usando o IB. O mesmo pode ser feito programaticamente, embora de forma bastante simples.

Uma maneira provavelmente mais fácil de conseguir isso (usando o IB):

Arraste um UIView para o seu TableView para torná-lo sua visualização de header.

  1. Definir essa altura da vista de header para 100 px
  2. Defina o tableview contentInset (top) como -100
  3. Os headers de seção agora rolam como qualquer célula comum.

Algumas pessoas comentaram dizendo que esta solução esconde o primeiro header, no entanto, eu não notei nenhum problema. Funcionou perfeitamente para mim e foi de longe a solução mais simples que vi até agora.

Eu não estava feliz com as soluções descritas até agora, então tentei combiná-las. O resultado é o seguinte código, inspirado em @awulf e @cescofry. Isso funciona para mim porque eu não tenho nenhum header de visualização de tabela real. Se você já tiver um header de exibição de tabela, talvez seja necessário ajustar a altura.

 // Set the edge inset self.tableView.contentInset = UIEdgeInsetsMake(-23.0f, 0, 0, 0); // Add a transparent UIView with the height of the section header (ARC enabled) [self.tableView setTableHeaderView:[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 23.0f)]]; 

Basta alterar o estilo TableView:

 self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped]; 

Documentação UITableViewStyle :

UITableViewStylePlain – Uma visualização de tabela simples. Quaisquer headers ou rodapés de seção são exibidos como separadores inline e flutuam quando a exibição de tabela é rolada.

UITableViewStyleGrouped – Uma exibição de tabela cujas seções apresentam grupos distintos de linhas. Os headers e rodapés da seção não flutuam.

Selecione o estilo TableView agrupado

Selecione o estilo de Exibição de Tabela Agrupada no Inspetor de Atributos do tableView no storyboard.

Mude o seu estilo TableView:

 self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped]; 

De acordo com a documentação da Apple para o UITableView:

UITableViewStylePlain – Uma visualização de tabela simples. Quaisquer headers ou rodapés de seção são exibidos como separadores inline e flutuam quando a exibição de tabela é rolada.

UITableViewStyleGrouped – Uma exibição de tabela cujas seções apresentam grupos distintos de linhas. Os headers e rodapés da seção não flutuam. Espero que esta pequena mudança irá ajudá-lo ..

Defina o headerView da tabela com uma visualização transparente com a mesma altura do header na visualização de seção. Também inicie a tableview com um quadro na altura.

 self.tableview = [[UITableView alloc] initWithFrame:CGRectMake(0, - height, 300, 400)]; UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)] autorelease]; [self.tableView setTableHeaderView:headerView]; 

Eu encontrei uma solução alternativa, use a primeira célula de cada seção em vez de uma seção de header real, esta solução não parece tão limpa, mas funciona tão bem, você pode usar uma célula protótipo definido para sua seção de headers e no método cellForRowAtIndexPath solicite o indexPath.row == 0, se true, use a célula de protótipo da seção de header, senão use sua célula protótipo padrão.

Agora que o estilo agrupado parece basicamente o mesmo que o estilo simples no iOS 7 (em termos de planicidade e plano de fundo), para nós, a melhor e mais fácil (ou seja, menos hacky) foi simplesmente alterar o estilo da visualização de tabela para agrupado. Jacking com contentInsets sempre foi um problema quando integramos uma barra de navegação de rolagem no topo. Com um estilo de exibição de tabela agrupada, ele parece exatamente o mesmo (com nossas células) e os headers da seção permanecem fixos. Nenhuma esquisitice de rolagem.

Atribua um valor negativo ao seu tableView. Se você tiver headers de seção altos de 22px e não quiser que fiquem grudentos, logo após você reloadData, adicione:

 self.tableView.contentInset = UIEdgeInsetsMake(-22, 0, 0, 0); self.tableView.contentSize = CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height+22); 

Funciona como um encanto para mim. Funciona também para rodapés de seção, apenas atribua a inserção negativa na parte inferior.

Eu adiciono a tabela a uma exibição de rolagem e parece funcionar bem.

Confira minha resposta aqui . Esta é a maneira mais fácil de implementar os headers de seção não flutuantes sem nenhum tipo de hacking.

A resposta da @ LocoMike melhor se encaixou na minha tableView, no entanto, quebrou ao usar rodapés também. Então, esta é a solução corrigida ao usar headers e rodapés:

 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return (self.sections.count + 1) * 3; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (section % 3 != 1) { return 0; } section = section / 3; ... } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { if (section % 3 != 0) { return nil; } section = section / 3; ... } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { if (section % 3 != 0) { return 0; } section = section / 3; ... } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { if (section % 3 != 2) { return 0; } section = section / 3; ... } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { if (section % 3 != 0) { return nil; } section = section / 3; ... } - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { if (section % 3 != 2) { return nil; } section = section / 3; ... } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { int section = indexPath.section; section = section / 3; ... } 

Mude o seu estilo TableView:

 self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped]; 

De acordo com a documentação da Apple para o UITableView:

 UITableViewStylePlain- A plain table view. Any section headers or footers are displayed as inline separators and float when the table view is scrolled. UITableViewStyleGrouped- A table view whose sections present distinct groups of rows. The section headers and footers do not float. Hope this small change will help you .. 

Versão rápida da resposta @awulf, que funciona muito bem!

 func scrollViewDidScroll(scrollView: UIScrollView) { let sectionHeight: CGFloat = 80 if scrollView.contentOffset.y <= sectionHeight { scrollView.contentInset = UIEdgeInsetsMake( -scrollView.contentOffset.y, 0, 0, 0) }else if scrollView.contentOffset.y >= sectionHeight { scrollView.contentInset = UIEdgeInsetsMake(-sectionHeight, 0, 0, 0) } } 

Eu aprendi que apenas definindo a propriedade tableHeaderView faz isso, ou seja:

  tableView.tableHeaderView = customView; 

e é isso.