Como resize um tableHeaderView de um UITableView?

Estou tendo problemas para resize um tableHeaderView. Simples não funciona.

1) Crie um UITableView e UIView (100 x 320 px);

2) Defina o UIView como tableHeaderView do UITableView;

3) Construa e vá. Está tudo bem.

Agora, quero resize o tableHeaderView, então incluo esse código no viewDidLoad:

self.tableView.autoresizesSubviews = YES; self.tableView.tableHeaderView = myHeaderView; self.tableView.tableFooterView = myFooterView; CGRect newFrame = self.tableView.tableHeaderView.frame; newFrame.size.height = newFrame.size.height + 100; self.tableView.tableHeaderView.frame = newFrame; 

A altura da tableHeaderView deve aparecer com 200, mas aparece com 100.

Se eu escrever:

 self.tableView.autoresizesSubviews = YES; CGRect newFrame = myHeaderView.frame; newFrame.size.height = newFrame.size.height + 100; myHeaderView.frame = newFrame; self.tableView.tableHeaderView = myHeaderView; self.tableView.tableFooterView = myFooterView; 

Então começa com 200 de altura, como eu quero. Mas eu quero poder modificá-lo em tempo de execução.

Eu também tentei isso sem sucesso:

 self.tableView.autoresizesSubviews = YES; self.tableView.tableHeaderView = myHeaderView; self.tableView.tableFooterView = myFooterView; CGRect newFrame = self.tableView.tableHeaderView.frame; newFrame.size.height = newFrame.size.height + 100; self.tableView.tableHeaderView.frame = newFrame; [self.tableView.tableHeaderView setNeedsLayout]; [self.tableView.tableHeaderView setNeedsDisplay]; [self.tableView setNeedsLayout]; [self.tableView setNeedsDisplay]; 

O ponto aqui é: Como redimensionamos um tableHeaderView em runtime ???

Alguém consegue fazer isso?

obrigado

iMe

FYI: Eu consegui isso para funcionar modificando o tableHeaderView e re-definindo-o. Nesse caso, estou ajustando o tamanho do tableHeaderView quando a subvisão UIWebView terminar de carregar.

 [webView sizeToFit]; CGRect newFrame = headerView.frame; newFrame.size.height = newFrame.size.height + webView.frame.size.height; headerView.frame = newFrame; [self.tableView setTableHeaderView:headerView]; 

Esta resposta é antiga e aparentemente não funciona no iOS 7 e acima.

Eu corri para o mesmo problema, e eu também queria que as mudanças fossem animadas, então criei uma subclass de UIView para minha visualização de header e adicionei estes methods:

 - (void)adjustTableHeaderHeight:(NSUInteger)newHeight{ NSUInteger oldHeight = self.frame.size.height; NSInteger originChange = oldHeight - newHeight; [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:1.0f]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, newHeight); for (UIView *view in [(UITableView *)self.superview subviews]) { if ([view isKindOfClass:[self class]]) { continue; } view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y - originChange, view.frame.size.width, view.frame.size.height); } [UIView commitAnimations]; } - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{ [(UITableView *)self.superview setTableHeaderView:self]; } 

Essencialmente, isso anima todas as subvisualizações do UITableView que não são do mesmo tipo de class que a class chamadora. No final da animação, ele chama setTableHeaderView no superview (o UITableView) – sem isso, o conteúdo do UITableView retornará na próxima vez que o usuário rolar. A única limitação que encontrei até agora é que, se o usuário tentar rolar o UITableView enquanto a animação estiver ocorrendo, a rolagem será animada como se a visualização do header não tivesse sido redimensionada (não é grande coisa se a animação for rápido).

Se você quiser animar condicionalmente as alterações, faça o seguinte:

 - (void) showHeader:(BOOL)show animated:(BOOL)animated{ CGRect closedFrame = CGRectMake(0, 0, self.view.frame.size.width, 0); CGRect newFrame = show?self.initialFrame:closedFrame; if(animated){ // The UIView animation block handles the animation of our header view [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:0.3]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; // beginUpdates and endUpdates trigger the animation of our cells [self.tableView beginUpdates]; } self.headerView.frame = newFrame; [self.tableView setTableHeaderView:self.headerView]; if(animated){ [self.tableView endUpdates]; [UIView commitAnimations]; } } 

Por favor, note que a animação é bidirecional:

  1. A animação das células abaixo da tableHeaderView . Isso é feito usando beginUpdates e endUpdates
  2. A animação da visualização real do header. Isso é feito usando um bloco de animação UIView .

A fim de sincronizar essas duas animações, o animationCurve tem que ser configurado para UIViewAnimationCurveEaseInOut e a duração para 0.3 , que parece ser o que o UITableView usa para sua animação.

Atualizar

Eu criei um projeto Xcode no gihub, que faz isso. Confira o projeto ResizeTableHeaderViewAnimated in besi / ios-quickies

captura de tela

Eu acho que deve funcionar se você apenas definir a altura do myHeaderView da seguinte forma:

 CGRect newFrame = myHeaderView.frame; newFrame.size.height = newFrame.size.height + 100; myHeaderView.frame = newFrame; self.tableView.tableHeaderView = myHeaderView; 

Usei a solução @garrettmoon acima até o iOS 7.
Aqui está uma solução atualizada baseada em @ garrettmoon’s:

 - (void)adjustTableHeaderHeight:(NSUInteger)newHeight animated:(BOOL)animated { [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:[CATransaction animationDuration]]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, newHeight); [(UITableView *)self.superview setTableHeaderView:self]; [UIView commitAnimations]; } - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{ [(UITableView *)self.superview setTableHeaderView:self]; } 

Isso funcionou para mim no iOS 7 e 8. Esse código está sendo executado no controlador de exibição de tabela.

 [UIView animateWithDuration:0.3 animations:^{ CGRect oldFrame = self.headerView.frame; self.headerView.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, oldFrame.size.width, newHeight); [self.tableView setTableHeaderView:self.headerView]; }]; 

É porque o setter de tableHeaderView.

Você precisa definir a altura do UIView antes de definir o tableHeaderView. (Seria muito mais fácil se a Apple abrir fonts deste framework …)

No iOS 9 e abaixo, tableHeaderView não seria re-layout após redimensioná-lo. Esse problema foi resolvido no iOS 10.

Para resolver este problema, basta fazê-lo com o seguinte código:

 self.tableView.tableHeaderView = self.tableView.tableHeaderView; 

No iOS 9.x, fazer isso no viewDidLoad funciona muito bem:

 var frame = headerView.frame frame.size.height = 11 // New size headerView.frame = frame 

headerView é declarado como @IBOutlet var headerView: UIView! e conectado no storyboard, onde é colocado no topo do tableView, para funcionar como tableHeaderView.

Definir a altura para a propriedade de exibição de header tableView.tableHeaderView no viewDidLoad não parece funcionar, a altura da exibição de header ainda não é alterada conforme o esperado.

Depois de lutar contra esse problema por muitas tentativas. Descobri que, você pode alterar a altura invocando a lógica de criação da visualização de header dentro do método - (void)didMoveToParentViewController:(UIViewController *)parent .

Então, o código de exemplo ficaria assim:

 - (void)didMoveToParentViewController:(UIViewController *)parent { [super didMoveToParentViewController:parent]; if ( _tableView.tableHeaderView == nil ) { UIView *header = [[[UINib nibWithNibName:@"your header view" bundle:nil] instantiateWithOwner:self options:nil] firstObject]; header.frame = CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), HeaderViewHeight); [_tableView setTableHeaderView:header]; } } 

Eu encontrei o inicializador initWithFrame de um UIView não homenageia corretamente o rect eu passar dentro Por isso, eu fiz o seguinte, que funcionou perfeitamente:

  - (id)initWithFrame:(CGRect)aRect { CGRect frame = [[UIScreen mainScreen] applicationFrame]; if ((self = [super initWithFrame:CGRectZero])) { // Ugly initialization behavior - initWithFrame will not properly honor the frame we pass self.frame = CGRectMake(0, 0, frame.size.width, 200); // ... } } 

A vantagem disso é que é melhor encapsulado em seu código de visualização.

Eu implementei a mudança de altura animada do header da tabela para expandir para a canvas geral quando tocada. No entanto, o código pode ajudar em outros casos:

 // Swift @IBAction func tapped(sender: UITapGestureRecognizer) { self.tableView.beginUpdates() // Required to update cells. // Collapse table header to original height if isHeaderExpandedToFullScreen { UIView.animateWithDuration(0.5, animations: { () -> Void in self.scrollView.frame.size.height = 110 // original height in my case is 110 }) } // Expand table header to overall screen else { let screenSize = self.view.frame // "screen" size UIView.animateWithDuration(0.5, animations: { () -> Void in self.scrollView.frame.size.height = screenSize.height }) } self.tableView.endUpdates() // Required to update cells. isHeaderExpandedToFullScreen= !isHeaderExpandedToFullScreen // Toggle } 

Cabeçalho de redimensionamento UITableView – UISearchBar com barra de escopo

Eu queria um UITableView com um UISearchBar como o header para a tabela, então eu tenho uma hierarquia que se parece com isso

 UITableView | |--> UIView | |--> UISearchBar | |--> UITableViewCells 

Métodos UISearchBarDelegate

Como foi dito em outro lugar, se você não definir o TableViewHeader após alterá-lo, nada acontecerá.

 - (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar { searchBar.showsScopeBar = YES; [UIView animateWithDuration:0.2f animations:^{ [searchBar sizeToFit]; CGFloat height = CGRectGetHeight(searchBar.frame); CGRect frame = self.tableView.tableHeaderView.frame; frame.size.height = height; self.tableHeaderView.frame = frame; self.tableView.tableHeaderView = self.tableHeaderView; }]; [searchBar setShowsCancelButton:YES animated:YES]; return YES; } - (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar { searchBar.showsScopeBar = NO; [UIView animateWithDuration:0.f animations:^{ [searchBar sizeToFit]; CGFloat height = CGRectGetHeight(searchBar.frame); CGRect frame = self.tableView.tableHeaderView.frame; frame.size.height = height; self.tableHeaderView.frame = frame; self.tableView.tableHeaderView = self.tableHeaderView; }]; [searchBar setShowsCancelButton:NO animated:YES]; return YES; } 

Se o costume headerView for projetado usando o autolayout e o headerView precisar ser atualizado após a busca da Web ou uma tarefa preguiçosa semelhante. então no iOS-Swift eu fiz isso e atualizei o meu headerView usando o seguinte código:

 //to reload your cell data self.tableView.reloadData() dispatch_async(dispatch_get_main_queue(),{ // this is needed to update a specific tableview's headerview layout on main queue otherwise it's won't update perfectly cause reloaddata() is called self.tableView.beginUpdates() self.tableView.endUpdates() } 

Obviamente, até agora a Apple deveria ter implementado o UITableViewAutomaticDimension para tableHeaderView & tableFooterView …

O seguinte parece funcionar para mim usando a (s) restrição (ões) do layout:

 CGSize s = [ self systemLayoutSizeFittingSize : UILayoutFittingCompressedSize ]; CGRect f = [ self frame ]; f.size = s; [ self setFrame : f ]; 

Você tentou [self.tableView reloadData] depois de alterar a altura?