IPhone: скрыть панель поиска UITableView по умолчанию

Я использовал построитель интерфейсов для создания табличного представления, к которому я добавил панель поиска библиотеки и контроллер отображения поиска, чтобы добавить функции поиска. Тем не менее, IB настроил его так, чтобы панель отображалась в верхней части экрана, когда сначала отображается представление.

Я хотел бы знать, как скрывать панель поиска по умолчанию, но все же прокручивается в виде таблицы (например, приложение Apple Mail). Я пробовал позвонить scrollRectToVisible:animated: в viewDidLoad, чтобы прокрутить представление таблицы вниз, но безрезультатно. Какой предпочтительный способ скрытия строки поиска по умолчанию?

Ответ 1

Сначала убедитесь, что добавьте UISearchBar в tableHeaderView UITableView, чтобы он прокручивался с содержимым таблицы и не был прикреплен к вершине представления.

Панель поиска не учитывается как строка в представлении таблицы, поэтому, если вы просматриваете верхнюю часть таблицы в первой строке, она "скрывает" панель поиска:

[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];

или в Swift:

yourTableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)

Обязательно не прокручивать представление таблицы перед тем, как он содержит данные (scrollToRowAtIndexPath приведет к возникновению исключения, если указанный индексный указатель не указывает на допустимую строку (т.е. если tableview пуст)).

Ответ 2

Не добавляйте UISearchBar в качестве подсмотра UITableView, это необязательно.

UITableView имеет свойство tableHeaderView, которое идеально подходит для этого:

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

Если вы не хотите видеть его по умолчанию:

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.tableView setContentOffset:CGPointMake(0, 44)];
}

Я также получаю кнопку отмены, чтобы скрыть ее снова.... (и удалите клавиатуру)

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
    [self.tableView setContentOffset:CGPointMake(0, 44) animated:YES];
    [self.searchBar resignFirstResponder];
}

Ответ 3

ContentOffset был отмечен в комментариях Тима и Джо Д'Арды, но это немного расширилось, добавив анимацию, чтобы скрыть панель поиска. Я заметил, что для панели поиска немного неожиданно просто исчезнуть.

Небольшое обновление для тех, кто хочет настроить iOS 4.0 и выше, попробуйте следующее:

[UIView animateWithDuration:0.4 animations:^{
    self.tableView.contentOffset = CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height);
 } completion:nil];

Предыдущий ответ:

[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];

Ответ 4

Есть много ответов на это решение, однако для меня это не очень хорошо.

Это прекрасно работает. Без анимации, и делается на -viewDidLoad

 - (void)viewDidLoad {
     [super viewDidLoad];
     self.tableView.contentOffset = CGPointMake(0,  self.searchBar.frame.size.height - self.tableView.contentOffset.y);
 }

Примечание:

В коде предполагается, что у вас есть searchBar @property, который связан с панелью поиска. Если нет, вы можете использовать self.searchDisplayController.searchBar вместо

Ответ 5

Для Swift 3 +

Я сделал это:

Объявите это var:

    var searchController = UISearchController()

И в методе viewDidLoad()

    searchController = 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)

Ответ 6

Моя цель состояла в том, чтобы скрыть панель поиска, добавленную в tableHeaderView, из обычного стиля TableView в раскадровке, когда контроллер просмотра загружен и отображает панель, когда пользователь прокручивает вниз вверху UITableView. Итак, я использую Swift и добавил расширение:

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

в viewDidLoad() просто звоните:

self.tableView.hideSearchBar()

Ответ 7

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

У меня searchBar установлен как tableHeaderView в сгруппированной таблице на iOS7. В viewDidLoad у меня есть tableView.contentOffset = CGPointMake(0, 44);, чтобы сохранить searchBar изначально "скрытым". Когда пользователь прокручивает вниз searchBar, dsiplayed

Цель: скрыть поискBar по кнопке отмены нажмите

В searchBarCancelButtonClicked(searchBar: UISearchBar!)

Это не сработало: [yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; tableView слишком сильно прокручивался, в результате строка 0 отставала от toolBar.

Это не сработало: tableView.ContentOffset = CGPointMake(0, 44) - ничего не происходит

Это не сработало: tableView.ContentOffset = CGPointMake(0, searchBar.frame.size.height) - ничего не происходит

Это не сработало: tableView.setContentOffset(CGPointMake(0, 44), animated: true); Снова tableView слишком сильно прокручивался, в результате строка 0 отставала от toolBar.

Это работало частично: tableView.setContentOffset(CGPointMake(0, 0), но titleForHeaderInSection шел за toolBar

ЭТО РАБОТАЕТ: tableView.setContentOffset(CGPointMake(0, -20)

Кажется, не логично, но только -20 переместил его на правильную позицию

Ответ 8

Все существующие решения не работают для меня на iOS 8, когда для заполнения таблицыView не хватает строк, так как iOS автоматически настраивает вставку в этой ситуации. (Существующие ответы хороши, когда есть достаточно строк)

После этого, как и 6 часов по этой проблеме, я наконец получил это решение.

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

Вот как я это сделал в Swift:

1.) объявить переменную minimumCellNum как свойство класса

var minimumCellNum: Int?

2.) вычислите minimumCellNum и установите tableView.contentOffset в viewWillAppear

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.) в tableView(tableView: UITableView, numberOfRowsInSection section: Int))

let numOfYourRows = YOUR LOGIC
if numOfYourRows > minimumCellNum {
    return numOfYourRows
} else {
    return minimumCellNum!
}

4.) Зарегистрируйте пустую ячейку, чей атрибут selection None, на раскадровке и в tableView(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.) в tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)

if tableView == self.tableView {
    if numOfYourRows < (indexPath.row + 1) {
        return
    }
    YOUR LOGIC OF SELECTING A CELL
}

Это не идеальное решение, но это единственное обходное решение, которое действительно работает для меня на iOS 8. Я хотел бы знать, есть ли более аккуратное решение.

Ответ 9

Смещение содержимого - это путь, но он не работает в течение 100% времени.

Это не работает, если установить estimatedRowHeight на фиксированное число. Я еще не знаю, как работать. Я создал проект , в котором указаны проблемы, и я создал radar с Apple.

Проверьте проект, если вы хотите быстро привести пример его установки.

Ответ 10

Обратите внимание, что принятый ответ сработает, если в представлении таблицы нет данных. И добавление его в viewDidLoad может не работать при определенных обстоятельствах.

[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; // crashes if no rows/data

Поэтому вместо этого добавьте эту строку кода:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    [yourTableView setContentOffset:CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height)];
}

Ответ 11

Честно говоря, ни один из ответов на самом деле не решил проблему (для меня). Если в вашем представлении таблицы нет строк или высота строки отличается, этих ответов недостаточно.

Единственное, что работает:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    self.tableView.contentOffset = (CGPoint){.y =  self.tableView.contentOffset.y + self.searchController.searchBar.frame.size.height};
}

Ответ 12

Я обнаружил, что приложение "Примечания" не может искать элементы, когда tableView пуст. Поэтому я думаю, что просто используя -(void)addSubview:(UIView *)view, чтобы сначала добавить пустую таблицу. Когда вы добавляете элемент в свой массив источников данных, он запускает еще один код кода для загрузки tableView.

Итак, мое решение:

if([self.arrayList count] > 0)
{
     [self.tableView reloadData];     //use jdandrea 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];
}

Надеюсь, что это поможет: -)

Ответ 13

Измените границы таблицыView, это можно сделать внутри viewDidLoad, и вам не нужно беспокоиться о том, является ли таблица пустой или нет (чтобы избежать исключения).

CGRect newBounds = self.tableView.bounds;
newBounds.origin.y = newBounds.origin.y + self.searchBar.bounds.size.height;
self.tableView.bounds = newBounds;

Как только пользователь прокрутит страницу вниз, появится панель поиска и будет вести себя нормально

Ответ 14

Другие ответы на этот вопрос либо вообще не работали для меня, имели странное поведение, когда tableView имел 0 строк, либо перепутал позицию прокрутки при перемещении между родительскими и вложенными позициями. Это сработало для меня (целью было скрыть UISearchBar при загрузке):

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

Объяснение
В любое время, когда появится tableView, этот код проверяет, видима ли UISearchBar (то есть позиция y позиции contentOffset, так называемая прокрутка, 0). Если это так, он просто прокручивает высоту поискового бара. Если searchBar не отображается (подумайте о большем списке элементов в tableView), он не будет пробовать и прокручивать tableView, так как это испортит позиционирование при возврате из вложенной позиции.

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

Ответ 15

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

let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)

self.tableView.selectRowAtIndexPath(firstIndexPath, анимированный: false, scrollPosition:.Top)

Если вы поместите вышеуказанный код в viewDidLoad, он выдает ошибку, потому что tableView еще не загружен, поэтому вы должны поместить его в viewDidAppear, потому что этот пункт tableView уже загружен.

Если вы положили его на viewDidAppear, каждый раз, когда вы открываете tableView, он будет прокручиваться вверх.

Может быть, вы не хотите этого поведения, если tableView остается открытым, например, когда он является UITabBar View Controller или когда вы выполняете segue, а затем возвращаетесь. Если вы просто хотите, чтобы он прокручивался вверху начальной загрузки, вы можете создать переменную, чтобы проверить, является ли она начальной нагрузкой, чтобы она прокручивалась вверху только один раз.

Определите сначала переменную с именем isInitialLoad в классе контроллера представления и установите ее равной "true":

var isInitialLoad = true

Затем проверьте, истинна ли isInitialLoad в viewDidAppear, и если это правда, прокрутите вверх и установите для переменной isInitialLoad значение false:

if isInitialLoad {
            let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)
            self.tableView.selectRowAtIndexPath(firstIndexPath, animated: false, scrollPosition: .Top)

            isInitialLoad = false
        }

Ответ 16

Ниже код работает для меня

self.tableView.contentOffset = CGPointMake(0.0, 44.0);

Ответ 17

Я попытался установить смещение содержимого и scrollToIndexpath, но ничего не получилось удовлетворительно. Я удалил параметр tableHeaderView как searchBar из viewDidLoad и установил его в делегате scrollview, как показано ниже

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

Это работало как шарм. Настройка смещения содержимого предназначена для плавной прокрутки

Ответ 18

Метод scrollToRowAtIndexPath вызывает сбой, если в таблице есть ноль строк.

UITableView - это просто представление с прокруткой, поэтому вы можете просто изменить смещение содержимого.

Это проверяет, что у вас есть панель поиска в качестве tableHeaderView, и предполагается, что вы делаете прокрутки, чтобы скрыть ее

    if let searchHeight = tableView.tableHeaderView?.frame.height {
        tableView.setContentOffset(CGPoint.init(x: 0, y:searchHeight ), animated: false)
    }

Ответ 19

Не забудьте принять строку состояния и навигационную панель. Мой контроллер табличного представления встроен в контроллер навигации в viewDidAppear:

tableView.contentOffset = CGPointMake(0, -20) // -20 = 44 (search bar height) - 20 (status bar height) - 44 (navigation bar height)

работал у меня.

Ответ 20

Для Swift:

Просто сделайте содержимое таблицы view y offset, которое должно быть похоже на высоту панели поиска.

self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height)

Ответ 21

Swift 3

работает и с пустой таблицей!

В моей среде я загружаю пользовательские ячейки с помощью xib файла, а rowHeight автоматически устанавливается.

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

Ответ 22

У меня была похожая проблема. И единственный способ решить эту проблему - использовать наблюдатель значения ключа для свойства contentOffset UITableView.

После некоторой отладки я понял, что проблема возникает, только если размер содержимого табличного представления меньше табличного. Я запускаю KVO, когда на viewWillAppear. И отправка остановить КВО через 0,3 секунды после появления. Каждый раз, когда contentOffset становится 0.0, KVO реагирует и устанавливает contentOffset на высоте панели поиска. Я отключаю KVO асинхронно через 0,3 секунды, потому что макет представления будет сбрасывать contentOffset даже после появления представления.

- (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"];
}