Użyłem Interface Builder do stworzenia widoku tabeli, do którego dodałem pasek wyszukiwania biblioteki i kontroler wyświetlania wyszukiwania, aby dodać funkcję wyszukiwania. Jednak IB skonfigurował go tak, aby pasek był widoczny u góry ekranu, gdy widok jest wyświetlany po raz pierwszy.
Chciałbym wiedzieć, jak domyślnie ukryć pasek wyszukiwania, ale nadal można go przewijać w widoku tabeli (zobacz przykład aplikacji Mail firmy Apple). Próbowałem nazywając scrollRectToVisible:animated:
w viewDidLoad
przewijać widok tabeli w dół, ale bezskutecznie. Jaki jest preferowany sposób domyślnego ukrywania paska wyszukiwania?
contentOffset
dowolnej wartości nie działa, jeśli używasz złożonego układu kontrolera widoku. Nie polecam tego.Nie dodawaj UISearchBar jako podwidoku UITableView, nie jest to konieczne.
UITableView ma właściwość tableHeaderView, która jest idealna do tego:
- (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; }
Jeśli nie chcesz go widzieć domyślnie:
- (void) viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.tableView setContentOffset:CGPointMake(0, 44)]; }
Dostaję również przycisk anulowania, aby ponownie go ukryć ... (i usunąć klawiaturę)
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { [self.tableView setContentOffset:CGPointMake(0, 44) animated:YES]; [self.searchBar resignFirstResponder]; }
źródło
viewWillAppear
jest złym pomysłem, ponieważ będzie się uruchamiać za każdym razem, gdy wrócisz do widoku. Oznacza to, że widok stołu będzie się powoli zmniejszał. Irytujący błąd!ContentOffset zostało odnotowane w komentarzach Tima i Joe D'Andrea, ale zostało to nieco rozszerzone poprzez dodanie animacji ukrywania paska wyszukiwania. Zauważyłem, że to trochę nieoczekiwane, że pasek wyszukiwania po prostu znika.
Mała aktualizacja dla tych, którzy chcą kierować reklamy na iOS 4.0 i nowsze, wypróbuj to:
[UIView animateWithDuration:0.4 animations:^{ self.tableView.contentOffset = CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height); } completion:nil];
Poprzednia odpowiedź:
[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];
źródło
viewDidAppear:
zamiastviewDidLoad
.Odpowiedzi na to rozwiązanie jest wiele, jednak żadna nie działała dobrze.
To działa doskonale. Brak animacji i jest wykonywana
-viewDidLoad
- (void)viewDidLoad { [super viewDidLoad]; self.tableView.contentOffset = CGPointMake(0, self.searchBar.frame.size.height - self.tableView.contentOffset.y); }
Uwaga:
Kod zakłada, że masz
searchBar
@property
link do paska wyszukiwania. Jeśli nie, możesz użyćself.searchDisplayController.searchBar
zamiast tegoźródło
-viewWillAppear
problem, jeśli nie działa .. Czy jest wywoływana, gdy kontroler kart przełącza się na widok?Dla Swift 3+
Ja to zrobiłem:
Oświadcz, że
var
:var searchController = UISearchController()
I w
viewDidLoad()
metodziesearchController = 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)
źródło
Moim celem było ukrycie paska wyszukiwania dodanego do tableHeaderView zwykłego stylu TableView w scenorysie, gdy kontroler widoku jest załadowany i wyświetlenie paska, gdy użytkownik przewinie w dół u góry UITableView. Więc używam Swift i dodałem rozszerzenie:
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) } } } }
w viewDidLoad () po prostu wywołaj:
self.tableView.hideSearchBar()
źródło
Wszystkie istniejące rozwiązania nie działają dla mnie na iOS 8, gdy nie ma wystarczającej liczby wierszy do wypełnienia tableView, ponieważ iOS dostosuje wstawkę automatycznie w tej sytuacji. (Istniejące odpowiedzi są dobre, gdy jest wystarczająco dużo wierszy)
Po zmarnowaniu 6 godzin na tę kwestię w końcu dostałem to rozwiązanie.
Krótko mówiąc, musisz wstawić puste komórki do tableView, jeśli nie ma wystarczającej liczby komórek, więc rozmiar zawartości tableView jest na tyle duży, że iOS nie dostosuje wstawki za Ciebie.
Oto, jak zrobiłem to w Swift:
1.) zadeklarować zmienną
minimumCellNum
jako właściwość klasyvar minimumCellNum: Int?
2.) Oblicz
minimumCellNum
i zestawtableView.contentOffset
wviewWillAppear
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.) w
tableView(tableView: UITableView, numberOfRowsInSection section: Int))
let numOfYourRows = YOUR LOGIC if numOfYourRows > minimumCellNum { return numOfYourRows } else { return minimumCellNum! }
4.) Zarejestruj pustą komórkę, której
selection
atrybutem jestNone
, w serii ujęć i wtableView(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.) w
tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
if tableView == self.tableView { if numOfYourRows < (indexPath.row + 1) { return } YOUR LOGIC OF SELECTING A CELL }
To nie jest idealne rozwiązanie, ale jest to jedyne obejście, które naprawdę działa dla mnie na iOS 8. Chciałbym wiedzieć, czy istnieje lepsze rozwiązanie.
źródło
Żadne z powyższych nie działało u mnie, więc na wszelki wypadek, gdyby ktoś miał ten sam problem.
Mam
searchBar
ustawionytableHeaderView
na stole zgrupowane na iOS7. WviewDidLoad
muszę początkowotableView.contentOffset = CGPointMake(0, 44);
zachowaćsearchBar
„ukrycie”. Gdy użytkownik przewinie w dół,searchBar
zostanie odtworzonyCel: ukryj pasek wyszukiwania po naciśnięciu przycisku anulowania
W
searchBarCancelButtonClicked(searchBar: UISearchBar!)
To nie zadziałało:
[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
tableView przewijał się zbyt mocno w górę, w wyniku czego wiersz 0 przeszedł za toolBar.To nie zadziałało:
tableView.ContentOffset = CGPointMake(0, 44)
- nic się nie dziejeTo nie zadziałało:
tableView.ContentOffset = CGPointMake(0, searchBar.frame.size.height)
- nic się nie dziejeTo nie zadziałało:
tableView.setContentOffset(CGPointMake(0, 44), animated: true);
ponownie tableView przewijał się zbyt mocno w górę, w wyniku czego wiersz 0 przeszedł za toolBar.To działało częściowo:
tableView.setContentOffset(CGPointMake(0, 0)
aletitleForHeaderInSection
znajdowało się za toolBaremTO DZIAŁAŁO:
tableView.setContentOffset(CGPointMake(0, -20)
Wydaje się to nielogiczne, ale tylko -20 przesunęło go na właściwą pozycję
źródło
CGRectGetHeight(searchBar.bounds)
?ContentOffset
rozwiązań nie zadziałaPrzesunięcie zawartości jest drogą do zrobienia, ale nie działa w 100% przypadków.
To nie działa, jeśli są ustawione
estimatedRowHeight
na stałą liczbę. Nie znam jeszcze pracy. Stworzyłem projekt pokazujący problem (y) i utworzyłem radar z Apple.Sprawdź projekt, jeśli chcesz mieć przykład, jak szybko to wszystko skonfigurować.
źródło
Zwróć uwagę, że zaakceptowana odpowiedź ulegnie awarii, jeśli w widoku tabeli nie ma danych. A dodanie go do viewDidLoad może nie działać w pewnych okolicznościach.
[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; // crashes if no rows/data
Dlatego zamiast tego dodaj ten wiersz kodu:
- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [yourTableView setContentOffset:CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height)]; }
źródło
Szczerze mówiąc, żadna z odpowiedzi tak naprawdę nie rozwiązała problemu (dla mnie). Jeśli w widoku tabeli nie ma wierszy LUB wysokość wiersza jest inna, te odpowiedzi nie wystarczą.
Jedyne, co działa:
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.tableView.contentOffset = (CGPoint){.y = self.tableView.contentOffset.y + self.searchController.searchBar.frame.size.height}; }
źródło
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
.scrollToRowAtIndexPath
Metoda powoduje awarię czy są zerowe wiersze w tabeli.UITableView to jednak tylko widok przewijania, więc możesz po prostu zmienić przesunięcie zawartości.
To sprawdza, czy masz coś jako tableHeaderView i zakładając, że przewijasz, aby to ukryć
if let searchHeight = tableView.tableHeaderView?.frame.height { tableView.setContentOffset(CGPoint.init(x: 0, y:searchHeight ), animated: false) }
źródło
Uważam, że aplikacja „Notatki” nie może wyszukiwać elementów, gdy tableView jest puste. Więc myślę, że
-(void)addSubview:(UIView *)view
najpierw używa się do dodania pustej tabeli. Po dodaniu elementu do jego tablicy źródła danych, uruchomi on kolejny fragment kodu w celu załadowania tableView.Więc moje rozwiązanie to:
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]; }
Mam nadzieję że to pomoże :-)
źródło
Zmień granice tableView, można to zrobić wewnątrz
viewDidLoad
i nie musisz się martwić, czy tabela jest pusta, czy nie (aby uniknąć wyjątku).CGRect newBounds = self.tableView.bounds; newBounds.origin.y = newBounds.origin.y + self.searchBar.bounds.size.height; self.tableView.bounds = newBounds;
Gdy użytkownik przewinie tabelę w dół, pojawi się pasek wyszukiwania i będzie się zachowywał normalnie
źródło
Inne odpowiedzi na to pytanie albo w ogóle nie działały, zachowywały się dziwnie, gdy tableView miało 0 wierszy, albo powodowały zakłócenia pozycji przewijania podczas przechodzenia między nadrzędnymi i zagnieżdżonymi elementami zamówienia. To zadziałało dla mnie (celem było ukrycie paska UISearchBar podczas ładowania):
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) } }
Objaśnienie
Za każdym razem, gdy
tableView
pojawi się pojawi się, ten kod sprawdza, czy UISearchBar jest widoczny (co oznacza, żey
pozycjacontentOffset
, czyli pozycja przewijania, to0
). Jeśli tak, po prostu przewija w dół wysokość paska wyszukiwania. Jeśli pasek wyszukiwania nie jest widoczny (pomyśl o większej liście elementów wtableView
), nie będzie próbował przewijać elementutableView
, ponieważ zepsułoby to pozycjonowanie po powrocie z zagnieżdżonego elementu zamówienia.Uwaga boczna
Zalecam umieszczenie tego kodu w oddzielnej metodzie, aby zapewnić pojedynczą odpowiedzialność i umożliwić ponowne użycie go w dowolnym momencie w kodzie.
źródło
Jeśli twoja tabela zawsze będzie miała co najmniej jeden wiersz, po prostu przewiń do pierwszego wiersza tabeli, a pasek wyszukiwania zostanie automatycznie ukryty.
let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.selectRowAtIndexPath (firstIndexPath, animated: false, scrollPosition: .Top)
Jeśli umieścisz powyższy kod w viewDidLoad , wyrzuci on błąd, ponieważ tableView jeszcze się nie załadował, więc musisz umieścić go w viewDidAppear, ponieważ w tym momencie tableView już się załadował.
Jeśli umieścisz go na viewDidAppear , za każdym razem, gdy otworzysz tableView, przewinie się on do góry.
Może nie chcesz tego zachowania, jeśli tableView pozostaje otwarty, na przykład gdy jest to kontroler widoku UITabBar lub gdy wykonujesz przepływ, a następnie wrócisz. Jeśli chcesz, aby przewijał się do góry podczas początkowego ładowania, możesz utworzyć zmienną, aby sprawdzić, czy jest to ładowanie początkowe, aby tylko raz przewinął na górę.
Najpierw zdefiniuj zmienną o nazwie isInitialLoad w klasie kontrolera widoku i ustaw ją na wartość „true”:
var isInitialLoad = true
Następnie sprawdź, czy isInitialLoad ma wartość true w viewDidAppear, a jeśli tak, przewiń do góry i ustaw zmienną isInitialLoad na false:
if isInitialLoad { let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0) self.tableView.selectRowAtIndexPath(firstIndexPath, animated: false, scrollPosition: .Top) isInitialLoad = false }
źródło
Poniższy kod działa dla mnie
self.tableView.contentOffset = CGPointMake(0.0, 44.0);
źródło
Próbowałem ustawić przesunięcie zawartości i scrollToIndexpath, ale nic nie działało zadowalająco. Usunąłem ustawienie tableHeaderView jako searchBar z viewDidLoad i ustawiłem go w delegacie scrollview jak poniżej
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) } }
To działało jak urok. Ustawienie przesunięcia zawartości służy do płynnego przewijania
źródło
Nie zapomnij wziąć pod uwagę paska stanu i paska nawigacji . Mój kontroler widoku tabeli jest osadzony w kontrolerze nawigacji w
viewDidAppear
:tableView.contentOffset = CGPointMake(0, -20) // -20 = 44 (search bar height) - 20 (status bar height) - 44 (navigation bar height)
pracował dla mnie.
źródło
Dla Swift:
Po prostu ustaw przesunięcie y zawartości tabeli, które powinno być podobne do wysokości paska wyszukiwania.
self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height)
źródło
Szybki 3
działa również z pustym stołem!
W moim środowisku ładuję komórki niestandardowe za pomocą pliku xib, a parametr rowHeight jest ustawiany automatycznie.
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) }
źródło
Miałem podobny problem. Jedynym sposobem rozwiązania tego problemu było użycie obserwatora wartości klucza we właściwości contentOffset UITableView.
Po pewnym debugowaniu zdałem sobie sprawę, że problem pojawia się tylko wtedy, gdy rozmiar zawartości widoku tabeli jest mniejszy niż widok tabeli. Uruchamiam KVO, gdy jest na viewWillAppear. I zatrzymanie wysyłki KVO 0,3 sekundy po pojawieniu się widoku. Za każdym razem, gdy contentOffset zmienił się na 0.0, KVO reaguje i ustawia contentOffset na wysokość paska wyszukiwania. Zatrzymuję asynchroniczne KVO po 0,3 sekundy, ponieważ układ widoku zresetuje contentOffset nawet po pojawieniu się widoku.
- (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"]; }
źródło