Подтвердить что ты не робот

Блокировка UISearchBar в верхней части UITableView, например Game Center

Вот эта замечательная функция в UITableViews в Game Center и в барах поиска у них на вершинах. В отличие от приложений, где панель поиска помещается в представление заголовка таблицы (поэтому она считается стандартной ячейкой таблицы), вместо этого она, похоже, прикреплена к родительской навигационной панели над ней. Поэтому при прокрутке таблицы панель поиска действительно перемещается, но если вы прокручиваете границы таблицы, панель поиска никогда не перестает касаться панели навигации.

Кто-нибудь знает, как это могло быть сделано? Мне было интересно, может ли Apple разместить как панель поиска, так и таблицу в представлении родительского прокрутки, но мне интересно, может ли это быть проще.

4b9b3361

Ответ 1

Ответ Боба отменен: он должен быть MIN (0, scrollView.contentOffset.y).

Кроме того, для правильной поддержки изменения размера (которое будет происходить при повороте), другие значения кадра должны быть повторно использованы.

-(void)scrollViewDidScroll:(UIScrollView *)scrollView 
{
    UISearchBar *searchBar = searchDisplayController.searchBar;
    CGRect rect = searchBar.frame;
    rect.origin.y = MIN(0, scrollView.contentOffset.y);
    searchBar.frame = rect;
}

Ответ 2

Вы можете поместить searchBar в заголовок таблицы и реализовать метод scrollViewDidScroll: (void) scrollViewDidScroll: (UIScrollView *) для элемента tableView. Выполнение чего-то подобного должно работать:

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

Если вы использовали searchDisplayController, вы бы получили доступ к поисковой панели, используя self.searchDisplayController.searchbar.

Ответ 3

В Swift 2.1 и 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
       }

Ответ 4

Вот еще один шаг, если вы хотите полностью эмулировать строки поиска в Game Center.

Если вы начинаете с отличного ответа friedenberg's, а также модификации followben для iOS 6+, упомянутых в комментариях, вам все равно нужно настроить функциональность, когда панель поиска сам активен.

В игровом центре строки поиска будут прокручиваться вместе с таблицей при прокрутке вниз, но будут оставаться фиксированными под панелью навигации, когда вы попытаетесь прокрутить страницу за границами таблицы. Однако, когда панель поиска активна и отображаются результаты поиска, панель поиска больше не прокручивается вместе с таблицей; он остается фиксированным на месте под панелью навигации.

Здесь полный код (для iOS 6+) для его реализации. (Если вы ориентируетесь на iOS 5 или ниже, вам не нужно обматывать UISearchBar в UIView)

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;
}

Вуаля! Теперь, когда панель поиска неактивна, она перемещается вместе с таблицей и остается фиксированной при попытке выйти за пределы таблицы. Когда он активен, он останется фиксированным на месте, как в Game Center.

Ответ 5

Все остальные ответы здесь предоставили мне полезную информацию, но никто из них не работал с использованием iOS 7.1. Вот упрощенная версия того, что сработало для меня:

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

Примечание. Если вы используете "pull up to refresh" в своем списке, вам нужно заменить scrollView.contentInset.top в scrollViewDidScroll: на константу, чтобы панель поиска могла прокручивать анимацию обновления.

Ответ 6

В то время как другие ответы кажутся полезными и частично выполняют задание, это не решает проблему, когда панель поиска не получает касания пользователя, потому что она перемещается за пределы своего родительского представления при изменении рамки.

Что еще хуже, когда вы нажимаете на панель поиска, чтобы сделать ее первым ответчиком, очень вероятно, что делегат tableView вызовет tableView:didSelectRowAtIndexPath: в ячейке, которая выложена под панелью поиска.

Чтобы устранить эти проблемы, описанные выше, вам нужно обернуть панель поиска в простой UIView, представление, которое способно обрабатывать штрихи, произошедшие за пределами его границ. Таким образом, вы можете передать эти штрихи в панель поиска.

Итак, сделаем это первым:

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)
  }
}

Сейчас у нас есть подкласс UIView с именем SearchBarView, который способен получать штрихи за пределами своих границ.

Во-вторых, мы должны поместить панель поиска в это новое представление, пока контроллер представления загружает его представление:

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
  }
}

Наконец, мы должны обновить рамку панели поиска, когда пользователь прокручивает вниз по виду таблицы, чтобы она оставалась неподвижной вверху:

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

Вот результат:

введите описание изображения здесь

-

Важное примечание. Если в вашем представлении таблицы есть разделы, они, вероятно, затенят вашу панель поиска, поэтому вам нужно принести панель поиска поверх них каждый раз, когда обновление таблицы bounds будет обновляться.

введите описание изображения здесь

viewDidLayoutSubviews - это хорошее место для этого:

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

-

Надеюсь, это поможет. Вы можете загрузить пример проекта из здесь.

Ответ 7

Если целью развертывания является iOS 9 и выше, вы можете использовать привязки и программно настроить UISearchBar и 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)
            ])
    }

Я предполагаю, что вы создаете UISearchBar и UITableView из кода, а не в раскадровке.