Blokowanie paska wyszukiwania Uisearch na górze widoku UITableView, takiego jak Game Center

Jest ta fajna funkcja w UITableViews w Game Center i paskach wyszukiwania, które mają na szczycie. W przeciwieństwie do aplikacji, w których pasek wyszukiwania jest umieszczony w widoku nagłówka tabeli (więc liczy się jako standardowa komórka tabeli), zamiast tego wydaje się być przykręcony do nadrzędnego paska nawigacyjnego nad nim. Tak więc podczas przewijania tabeli pasek wyszukiwania rzeczywiście się przesuwa, ale jeśli przewijasz ponad granicami tabeli, pasek wyszukiwania nigdy nie przestaje dotykać paska nawigacji.

Czy ktoś wie jak to mogło być zrobione? Zastanawiałem się, czy Apple może umieścić zarówno pasek wyszukiwania i tabelę w widoku przewijania nadrzędnego, ale zastanawiam się, czy może to być prostsze niż to.

Author: nevan king, 2011-02-02

7 answers

ODPOWIEDŹ Boba jest odwrócona: powinno być MIN (0, scrollView.contentOffset.y).

Ponadto, aby poprawnie obsługiwać zmiany rozmiaru (które nastąpiłyby po obróceniu), należy ponownie użyć innych wartości ramki.

-(void)scrollViewDidScroll:(UIScrollView *)scrollView 
{
    UISearchBar *searchBar = searchDisplayController.searchBar;
    CGRect rect = searchBar.frame;
    rect.origin.y = MIN(0, scrollView.contentOffset.y);
    searchBar.frame = rect;
}
 28
Author: friedenberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-12 21:00:48

Można umieścić pasek wyszukiwania w nagłówku tabeli i zaimplementować metodę - (void)scrollViewDidScroll:(UIScrollView *)scrollView delegate dla widoku tabeli. Robienie czegoś takiego powinno zadziałać:

-(void) scrollViewDidScroll:(UIScrollView *)scrollView {
    searchBar.frame = CGRectMake(0,MAX(0,scrollView.contentOffset.y),320,44);
} 

Jeśli użyłeś kontrolera searchDisplayController, uzyskałbyś dostęp do paska wyszukiwania używając self.searchDisplayController.pasek wyszukiwania.

 7
Author: Bob Vork,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-03 16:08:39

W Swift 2.1 i iOS 9.2.1

    let searchController = UISearchController(searchResultsController: nil)

        override func viewDidLoad() {
        /* Search controller parameters */
            searchController.searchResultsUpdater = self  // This protocol allows your class to be informed as text changes within the UISearchBar.
            searchController.dimsBackgroundDuringPresentation = false  // In this instance,using current view to show the results, so do not want to dim current view.
            definesPresentationContext = true   // ensure that the search bar does not remain on the screen if the user navigates to another view controller while the UISearchController is active.

            let tableHeaderView: UIView = UIView.init(frame: searchController.searchBar.frame)
            tableHeaderView.addSubview(searchController.searchBar)
            self.tableView.tableHeaderView = tableHeaderView

        }
        override func scrollViewDidScroll(scrollView: UIScrollView) {
           let searchBar:UISearchBar = searchController.searchBar
           var searchBarFrame:CGRect = searchBar.frame
           if searchController.active {
              searchBarFrame.origin.y = 10
           }
           else {
             searchBarFrame.origin.y = max(0, scrollView.contentOffset.y + scrollView.contentInset.top)

           }
           searchController.searchBar.frame = searchBarFrame
       }
 5
Author: Muhammad Qasim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-22 14:49:30

Jest jeszcze jeden krok, jeśli chcesz w pełni emulować paski wyszukiwania w Game Center.

Jeśli zaczniesz odfriedenberga doskonała odpowiedź, a takżepodążaj za modyfikacji dla iOS 6+ wspomniano w komentarzach, nadal trzeba dostosować funkcjonalność, gdy sam pasek wyszukiwania jest aktywny.

W Game Center paski wyszukiwania będą przewijać się wraz ze stołem podczas przewijania w dół, ale pozostaną ustawione pod paskiem nawigacyjnym podczas próby przewinięcia w górę granice tabeli. Jednakże, gdy pasek wyszukiwania jest aktywny i wyświetlane są wyniki wyszukiwania, pasek wyszukiwania nie przewija się wraz z tabelą; pozostaje ustalony na miejscu poniżej paska nawigacyjnego .

Oto kompletny kod (dla iOS 6+) do implementacji tego. (Jeśli celujesz w system iOS 5 lub poniżej, nie musisz owijać paska UISearchBar w widoku interfejsu)

CustomTableViewController.m

- (void)viewDidLoad
{
    UISearchBar *searchBar = [[UISearchBar alloc] init];
    ...
    UIView *tableHeaderView = [[UIView alloc] initWithFrame:searchBar.frame];
    [tableHeaderView addSubview:searchBar];

    [self.tableView setTableHeaderView:tableHeaderView];
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    UISearchBar *searchBar = self.tableView.tableHeaderView.subviews.lastObject;
    CGRect searchBarFrame = searchBar.frame;

    /*
     * In your UISearchBarDelegate implementation, set a boolean flag when
     * searchBarTextDidBeginEditing (true) and searchBarTextDidEndEditing (false)
     * are called.
     */

    if (self.inSearchMode)
    {
        searchBarFrame.origin.y = scrollView.contentOffset.y;
    }
    else
    {
        searchBarFrame.origin.y = MIN(0, scrollView.contentOffset.y);
    }

    searchBar.frame = searchBarFrame;
}

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
    self.inSearchMode = YES;
}

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
    self.inSearchMode = NO;
}
Voila! Teraz, gdy pasek wyszukiwania jest nieaktywny przesunie się wraz ze stołem i pozostanie stały podczas próby przekroczenia granic stołu. Gdy jest aktywny, pozostanie na swoim miejscu, tak jak w Game Center.
 3
Author: Nick Schneble,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-29 12:51:58

Podczas gdy inne odpowiedzi wydają się pomocne i częściowo wykonują zadanie, nie rozwiązuje problemu paska wyszukiwania, który nie odbiera dotknięć użytkownika, ponieważ przesuwa się poza granice swojego widoku nadrzędnego podczas zmiany ramki.

Co gorsza, po kliknięciu paska wyszukiwania, aby uczynić go pierwszym odpowiedzialnym, jest bardzo prawdopodobne, że delegat tableView wywoła tableView:didSelectRowAtIndexPath: na komórkę, która jest umieszczona pod paskiem wyszukiwania.

Aby rozwiązać te problemy opisane powyżej, musisz aby owinąć pasek wyszukiwania w zwykły widok UIView, widok, który jest zdolny do przetwarzania dotknięć wystąpił poza jego granicami. W ten sposób możesz przekazać te dotknięcia do paska wyszukiwania.

Więc zróbmy to najpierw:

class SearchBarView: UIView {
  override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
    for subview in subviews {
      if !subview.userInteractionEnabled { continue }

      let newPoint = subview.convertPoint(point, fromView: self)
      if CGRectContainsPoint(subview.bounds, newPoint) {
        return subview.hitTest(newPoint, withEvent: event)
      }
    }
    return super.hitTest(point, withEvent: event)
  }
}

W tej chwili mamy podklasę UIView o nazwie SearchBarView, która jest w stanie odbierać dotknięcia występujące poza jej granicami.

Po drugie, powinniśmy umieścić pasek wyszukiwania w tym nowym widoku, podczas gdy kontroler widoku ładuje swój widok:

class TableViewController: UITableViewController {
  private let searchBar = UISearchBar(frame: CGRectZero)
  ...

  override func viewDidLoad() {
    super.viewDidLoad()
    ...
    searchBar.sizeToFit()
    let searchBarView = SearchBarView(frame: searchBar.bounds)
    searchBarView.addSubview(searchBar)

    tableView.tableHeaderView = searchBarView
  }
}

At na koniec powinniśmy zaktualizować ramkę paska wyszukiwania, Gdy użytkownik przewija widok tabeli w dół, aby pozostała stała na górze:

override func scrollViewDidScroll(scrollView: UIScrollView) {
  searchBar.frame.origin.y = max(0, scrollView.contentOffset.y)
}

Oto wynik:

Tutaj wpisz opis obrazka

--

Ważna uwaga: jeśli twój widok tabeli zawiera sekcje, prawdopodobnie będą one cieniem paska wyszukiwania, więc musisz umieścić pasek wyszukiwania na nich za każdym razem, gdy widok tabeli bounds zostanie zaktualizowany.

Tutaj wpisz opis obrazka

viewDidLayoutSubviews is a good place to do że:

override func viewDidLayoutSubviews() {
  super.viewDidLayoutSubviews()
  ...
  if let tableHeaderView = tableView.tableHeaderView {
    tableView.bringSubviewToFront(tableHeaderView)
  }
}

--

Mam nadzieję, że to pomoże. Przykładowy projekt można pobrać z tutaj .
 1
Author: ozgur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-28 15:14:20

Wszystkie inne odpowiedzi dostarczyły mi przydatnych informacji, ale żadna z nich nie działała przy użyciu iOS 7.1. Oto uproszczona wersja tego, co dla mnie działało:

MyViewController.h:

@interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchDisplayDelegate> {
}
@end

MyViewController.m:

@implementation MyViewController {

    UITableView *tableView;
    UISearchDisplayController *searchDisplayController;
    BOOL isSearching;
}

-(void)viewDidLoad {
    [super viewDidLoad];

    UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
    searchBar.delegate = self;

    searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
    searchDisplayController.delegate = self;
    searchDisplayController.searchResultsDataSource = self;
    searchDisplayController.searchResultsDelegate = self;

    UIView *tableHeaderView = [[UIView alloc] initWithFrame:searchDisplayController.searchBar.frame];
    [tableHeaderView addSubview:searchDisplayController.searchBar];
    [tableView setTableHeaderView:tableHeaderView];

    isSearching = NO;
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {

    UISearchBar *searchBar = searchDisplayController.searchBar;
    CGRect searchBarFrame = searchBar.frame;

    if (isSearching) {
        searchBarFrame.origin.y = 0;
    } else {
        searchBarFrame.origin.y = MAX(0, scrollView.contentOffset.y + scrollView.contentInset.top);
    }

    searchDisplayController.searchBar.frame = searchBarFrame;
}

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
    isSearching = YES;
}

-(void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
    isSearching = NO;
}

@end

Uwaga: Jeśli używasz "pull down to refresh"na liście, musisz zastąpić scrollView.contentInset.top w scrollViewDidScroll: stałą, aby pasek wyszukiwania mógł przewijać animację odświeżania.

 0
Author: Brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-24 22:04:29

Jeśli twoim celem wdrożenia jest system iOS 9 lub wyższy, możesz użyć kotwic i programowo ustawić pasek UISearchBar i UITableView:

    private let tableView = UITableView(frame: .zero, style: .plain)
    private let searchBar = UISearchBar(frame: CGRect .zero)

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.delegate = self
        tableView.dataSource = self
        tableView.contentInset = UIEdgeInsets(top: 44.0, left: 0.0, bottom: 0.0, right: 0.0)

        searchBar.delegate = self
        view.addSubview(tableView)
        view.addSubview(searchBar)
        NSLayoutConstraint.activate([
            searchBar.heightAnchor.constraint(equalToConstant: 44.0),
            searchBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            searchBar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            searchBar.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor)
            ])
    }

Zakładam, że tworzysz UISearchBar i UITableView z kodu, a nie w storyboardzie.

 0
Author: Filipp Ignatov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-17 10:55:38