Usei o Interface Builder para criar uma visualização de tabela, à qual adicionei a Barra de Pesquisa e o Controlador de Exibição de Pesquisa da biblioteca para adicionar a funcionalidade de pesquisa. No entanto, o IB o configurou de forma que a barra fique visível na parte superior da tela quando a visualização for exibida pela primeira vez.
Gostaria de saber como fazer com que a barra de pesquisa fique oculta por padrão, mas ainda seja rolável com a visualização da tabela (consulte o aplicativo Mail da Apple para obter um exemplo). Eu tentei chamar scrollRectToVisible:animated:
em viewDidLoad
para rolar a exibição de tabela para baixo, mas sem sucesso. Qual é a maneira preferida de ocultar a barra de pesquisa por padrão?
contentOffset
com qualquer valor será interrompida se você estiver empregando um layout de controlador de visualização complexo. Eu não recomendo.Não adicione o UISearchBar como uma subvisão do UITableView, isso não é necessário.
O UITableView tem uma propriedade tableHeaderView perfeita para isso:
- (void) viewDidLoad { [super viewDidLoad]; self.searchBar = [[[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)] autorelease]; self.searchBar.showsCancelButton = YES; self.searchBar.delegate = self; self.tableView.tableHeaderView = self.searchBar; }
Se você não quiser ver por padrão:
- (void) viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.tableView setContentOffset:CGPointMake(0, 44)]; }
Também recebo o botão Cancelar para ocultá-lo novamente .... (e remover o teclado)
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { [self.tableView setContentOffset:CGPointMake(0, 44) animated:YES]; [self.searchBar resignFirstResponder]; }
fonte
viewWillAppear
é uma má ideia, porque ele será executado toda vez que você navegar de volta para sua visualização. Isso significa que seu tableview irá diminuir lentamente. Bug irritante!O contentOffset foi observado nos comentários de Tim e Joe D'Andrea, mas é um pouco expandido com a adição de uma animação para ocultar a barra de pesquisa. Percebi que é um pouco inesperado para a barra de pesquisa simplesmente desaparecer.
Uma pequena atualização para aqueles que desejam direcionar o iOS 4.0 e superior, tente isto:
[UIView animateWithDuration:0.4 animations:^{ self.tableView.contentOffset = CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height); } completion:nil];
Resposta anterior:
[UIView beginAnimations:@"hidesearchbar" context:nil]; [UIView setAnimationDuration:0.4]; [UIView setAnimationBeginsFromCurrentState:YES]; self.tableView.contentOffset = CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height); [UIView commitAnimations];
fonte
viewDidAppear:
vez deviewDidLoad
.Existem muitas respostas para esta solução, porém nenhuma funcionou muito bem para mim.
Isso funciona perfeitamente. Sem animação e é feito em
-viewDidLoad
- (void)viewDidLoad { [super viewDidLoad]; self.tableView.contentOffset = CGPointMake(0, self.searchBar.frame.size.height - self.tableView.contentOffset.y); }
Nota:
O código presume que você tenha o
searchBar
@property
que está vinculado à barra de pesquisa. Se não, você pode usarself.searchDisplayController.searchBar
em vezfonte
-viewWillAppear
não funcionar. Ele é chamado quando o controlador de guia muda para a visualização?Para Swift 3+
Eu fiz isso:
Declare isto
var
:var searchController = UISearchController()
E no
viewDidLoad()
métodosearchController = UISearchController(searchResultsController: nil) searchController.searchResultsUpdater = self searchController.hidesNavigationBarDuringPresentation = false searchController.dimsBackgroundDuringPresentation = true searchController.searchBar.placeholder = NSLocalizedString("Search", comment: "") definesPresentationContext = true tableView.tableHeaderView = searchController.searchBar tableView.contentOffset = CGPoint(x: 0, y: searchController.searchBar.frame.size.height)
fonte
Meu objetivo era ocultar a barra de pesquisa adicionada a tableHeaderView do estilo de TableView simples no storyboard quando o controlador de visualização é carregado e mostrar a barra quando o usuário rola para baixo na parte superior de UITableView. Então, estou usando o Swift e adicionou uma extensão:
extension UITableView { func hideSearchBar() { if let bar = self.tableHeaderView as? UISearchBar { let height = CGRectGetHeight(bar.frame) let offset = self.contentOffset.y if offset < height { self.contentOffset = CGPointMake(0, height) } } } }
em viewDidLoad () basta chamar:
self.tableView.hideSearchBar()
fonte
Todas as soluções existentes não funcionam para mim no iOS 8 quando não há linhas suficientes para preencher o tableView, já que o iOS ajustará o inset automaticamente nesta situação. (No entanto, as respostas existentes são boas quando há linhas suficientes)
Depois de perder 6 horas com esse problema, finalmente consegui essa solução.
Resumindo, você precisa inserir células vazias em tableView se não houver células suficientes, então o tamanho do conteúdo de tableView é grande o suficiente para que o iOS não ajuste o inset para você.
Aqui está como eu fiz no Swift:
1.) declarar uma variável
minimumCellNum
como uma propriedade de classevar minimumCellNum: Int?
2.) calcular
minimumCellNum
e definirtableView.contentOffset
emviewWillAppear
let screenHeight = Int(UIScreen.mainScreen().bounds.height) // 101 = Height of Status Bar(20) + Height of Navigation Bar(44) + Height of Tab Bar(49) // you may need to subtract the height of other custom views from the screenHeight. For example, the height of your section headers. self.minimumCellNum = (screenHeight - 103 - heightOfOtherCustomView) / heightOfYourCell self.tableView.contentOffset = CGPointMake(0, 44)
3.) em
tableView(tableView: UITableView, numberOfRowsInSection section: Int))
let numOfYourRows = YOUR LOGIC if numOfYourRows > minimumCellNum { return numOfYourRows } else { return minimumCellNum! }
4.) Registre uma célula vazia, cujo
selection
atributo sejaNone
, no storyboard e emtableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
if indexPath.row < numOfYourRows { return YOUR CUSTOM CELL } else { let cell = tableView.dequeueReusableCellWithIdentifier("EmptyCell", forIndexPath: indexPath) as! UITableViewCell return cell }
5.) em
tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
if tableView == self.tableView { if numOfYourRows < (indexPath.row + 1) { return } YOUR LOGIC OF SELECTING A CELL }
Esta não é uma solução perfeita, mas é a única solução alternativa que realmente funciona para mim no iOS 8. Gostaria de saber se existe uma solução mais limpa.
fonte
Nenhuma das opções acima funcionou para mim, apenas no caso de alguém ter o mesmo problema.
Eu
searchBar
configurei comotableHeaderView
em uma tabela agrupada no iOS7. EmviewDidLoad
que tenhotableView.contentOffset = CGPointMake(0, 44);
de mantersearchBar
inicialmente "escondido". Quando o usuário rola para baixo,searchBar
é exibidoObjetivo: ocultar a barra de pesquisa ao tocar no botão Cancelar
Dentro
searchBarCancelButtonClicked(searchBar: UISearchBar!)
Isso não funcionou:
[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
tableView estava rolando muito para cima, resultando na linha 0 ficando atrás da barra de ferramentas.Isso não funcionou:
tableView.ContentOffset = CGPointMake(0, 44)
- nada aconteceIsso não funcionou:
tableView.ContentOffset = CGPointMake(0, searchBar.frame.size.height)
- nada aconteceIsso não funcionou:
tableView.setContentOffset(CGPointMake(0, 44), animated: true);
novamente, tableView estava rolando muito para cima, resultando na linha 0 ficando atrás da barra de ferramentas.Isso funcionou parcialmente:
tableView.setContentOffset(CGPointMake(0, 0)
mastitleForHeaderInSection
estava indo para trás da barra de ferramentasISSO FUNCIONOU:
tableView.setContentOffset(CGPointMake(0, -20)
Não parece lógico, mas apenas -20 o moveu para a posição correta
fonte
CGRectGetHeight(searchBar.bounds)
?ContentOffset
soluções funcionaráO deslocamento de conteúdo é o caminho a percorrer, mas não funciona 100% do tempo.
Não funciona se estiver configurando
estimatedRowHeight
para um número fixo. Eu não sei como funciona ainda. Eu criei um projeto mostrando o (s) problema (s) e criei um radar com a Apple.Confira o projeto se quiser um exemplo rápido de como configurar tudo.
fonte
Observe que a resposta aceita travará se não houver dados no tableview. E adicioná-lo ao viewDidLoad pode não funcionar em certas circunstâncias.
[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; // crashes if no rows/data
Portanto, em vez disso, adicione esta linha de código:
- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [yourTableView setContentOffset:CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height)]; }
fonte
Honestamente, nenhuma das respostas realmente resolveu o problema (para mim). Se a visualização da tabela não tiver linhas OU a altura das linhas for diferente, essas respostas não serão suficientes.
A única coisa que funciona:
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.tableView.contentOffset = (CGPoint){.y = self.tableView.contentOffset.y + self.searchController.searchBar.frame.size.height}; }
fonte
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
.O
scrollToRowAtIndexPath
método causa um travamento se não houver nenhuma linha na tabela.UITableView é apenas uma visualização de rolagem, portanto, você pode simplesmente alterar o deslocamento do conteúdo.
Isso verifica se você tem algo como seu tableHeaderView e, supondo que você role para ocultá-lo
if let searchHeight = tableView.tableHeaderView?.frame.height { tableView.setContentOffset(CGPoint.init(x: 0, y:searchHeight ), animated: false) }
fonte
Acho que o aplicativo "Notes" não consegue pesquisar itens quando tableView está em branco. Então eu acho que é só usar
-(void)addSubview:(UIView *)view
para adicionar uma tabela em branco no início. Quando você adiciona um item à sua matriz de fonte de dados, ele executa outro trecho de código para carregar o tableView.Então, minha solução é:
if([self.arrayList count] > 0) { [self.tableView reloadData]; //use jdandrea's code to scroll view when cell==nil in cellForRowAtIndexPath self.tableView.scrollEnabled = YES; } else { tableBlank = [[UITableView alloc]initWithFrame:CGRectMake(0,0,320,416) style:UITableViewStylePlain] autorelease]; tableBlank.delegate = self; tableBlank.dataSource = self; [self.view addSubview:tableBlank]; }
Espero que isto ajude :-)
fonte
Altere os limites do tableView, isso pode ser feito internamente
viewDidLoad
e você não precisa se preocupar se a tabela está vazia ou não (para evitar a exceção).CGRect newBounds = self.tableView.bounds; newBounds.origin.y = newBounds.origin.y + self.searchBar.bounds.size.height; self.tableView.bounds = newBounds;
Assim que o usuário rolar a tabela para baixo, a barra de pesquisa aparecerá e se comportará normalmente
fonte
As outras respostas a essa pergunta não funcionaram para mim, tiveram um comportamento estranho quando tableView tinha 0 linhas ou bagunçaram a posição de rolagem ao ir e voltar entre os itens de linha pai e aninhados. Isso funcionou para mim (o objetivo era ocultar o UISearchBar durante o carregamento):
public override func viewWillAppear(animated: Bool) { if self.tableView.contentOffset.y == 0 { self.tableView.contentOffset = CGPoint(x: 0.0, y: self.searchBar.frame.size.height) } }
Explicação
Sempre
tableView
que aparecerá, este código verifica se o UISearchBar está visível (ou seja, ay
posição docontentOffset
, também conhecido como posição de rolagem, é0
). Se estiver, ele simplesmente rola para baixo na altura da barra de pesquisa. Se a barra de pesquisa não estiver visível (pense em uma lista maior de itenstableView
), ela não tentará rolar otableView
, pois isso bagunçaria o posicionamento quando você retornar de um item de linha aninhado.Observação lateral
Eu recomendo colocar este código em um método separado para garantir a responsabilidade única e dar a você a capacidade de reutilização para chamá-lo a qualquer momento em seu código.
fonte
Se a sua tabela sempre terá pelo menos uma linha, basta rolar até a primeira linha da tabela e a barra de pesquisa será ocultada automaticamente.
let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.selectRowAtIndexPath (firstIndexPath, animated: false, scrollPosition: .Top)
Se você colocar o código acima em viewDidLoad , ele gerará um erro porque a tableView ainda não foi carregada, então você deve colocá-la em viewDidAppear porque a esta altura a tableView já foi carregada.
Se você colocá-lo em viewDidAppear , toda vez que você abrir o tableView, ele rolará para o topo.
Talvez você não queira este comportamento se o tableView permanecer aberto, como quando é um UITabBar View Controller ou quando você faz uma segue e depois volta. Se você deseja apenas rolar para o topo da carga inicial, pode criar uma variável para verificar se é uma carga inicial, de forma que role para o topo apenas uma vez.
Defina primeiro uma variável chamada isInitialLoad na classe do controlador de visualização e defina-a igual a "true":
var isInitialLoad = true
Em seguida, verifique se isInitialLoad é verdadeiro em viewDidAppear e, se for verdadeiro, role para o topo e defina a variável isInitialLoad como falsa:
if isInitialLoad { let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0) self.tableView.selectRowAtIndexPath(firstIndexPath, animated: false, scrollPosition: .Top) isInitialLoad = false }
fonte
O código abaixo está funcionando para mim
self.tableView.contentOffset = CGPointMake(0.0, 44.0);
fonte
Tentei definir o deslocamento de conteúdo e scrollToIndexpath, mas nada funcionou de forma satisfatória. Removi a configuração de tableHeaderView como searchBar de viewDidLoad e a defini no delegado scrollview como abaixo
override func scrollViewWillBeginDragging(scrollView: UIScrollView) { if scrollView.contentOffset.y < 0 && tableView.tableHeaderView == nil { tableView.tableHeaderView = searchController.searchBar tableView.setContentOffset(CGPointMake(0, scrollView.contentOffset.y + searchController.searchBar.frame.size.height), animated: false) } }
Isso funcionou perfeitamente. A configuração de deslocamento de conteúdo é para propósitos de rolagem suave
fonte
Não se esqueça de levar a barra de status e a barra de navegação em consideração. Meu controlador de visualização de tabela está embutido em um controlador de navegação, em
viewDidAppear
:tableView.contentOffset = CGPointMake(0, -20) // -20 = 44 (search bar height) - 20 (status bar height) - 44 (navigation bar height)
trabalhou para mim.
fonte
Para Swift:
Basta fazer com que o conteúdo do tableview seja deslocado, que deve ser como a altura da barra de pesquisa.
self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height)
fonte
Swift 3
funciona com a mesa vazia também!
No meu ambiente, eu carrego células personalizadas por arquivo xib e o rowHeight é definido automaticamente.
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { self.tableView.contentOffset = CGPoint(x: 0, y: self.tableView.contentOffset.y + self.searchController.searchBar.bounds.height) }
fonte
Eu tive um problema semelhante. E a única maneira que encontrei de resolver esse problema foi usar o observador de valor-chave na propriedade UITableView contentOffset.
Depois de alguma depuração, percebi que o problema aparece apenas se o tamanho do conteúdo do table view for menor do que o tableview. Eu inicio KVO quando em viewWillAppear. E despache a parada KVO 0,3 segundos após o aparecimento da vista. Cada vez que contentOffset torna-se 0,0, o KVO reage e define contentOffset na altura da barra de pesquisa. Eu paro o KVO assíncrono após 0,3 segundos porque o layout de exibição irá redefinir o contentOffset mesmo após a exibição de exibição.
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil]; } -(void)viewDidAppear:(BOOL)animated{ __weak typeof (self) weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [weakSelf.tableView removeObserver:self forKeyPath:@"contentOffset"];}); } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if ([keyPath isEqualToString:@"contentOffset"] && self.tableView.contentOffset.y == 0.0) { self.tableView.contentOffset = CGPointMake(0, CGRectGetHeight(self.tableView.tableHeaderView.frame)); } } -(void)dealloc { [self.tableView removeObserver:self forKeyPath:@"contentOffset"]; }
fonte