it-swarm.com.ru

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

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

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

85
Tim

Сначала убедитесь, что добавили 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 вызовет исключение, если заданный indexPath не указывает на допустимую строку (то есть, если табличное представление пусто)).

115
Zargony

Не добавляйте 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];
}
45
bandejapaisa

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

25
Andrei

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

Это работает отлично. Нет анимации, и выполняется по -viewDidLoad

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

Заметка:

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

7
code ninja

Для 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
Dasoga

Моя цель состояла в том, чтобы скрыть панель поиска, добавленную к 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()
5
HotJard

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

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

Проверьте проект, если вам нужен пример в Swift, как все это настроить.

4
RyanJM

Все существующие решения не работают для меня на iOS 8, когда не хватает строк для заполнения tableView, так как 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.) Зарегистрируйте пустую ячейку с атрибутом selectionNone в раскадровке и в 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. Я хотел бы знать, есть ли более аккуратное решение.

4
Brian

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

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

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

В searchBarCancelButtonClicked(searchBar: UISearchBar!)

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

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

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

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

Это работало частично: tableView.setContentOffset(CGPointMake(0, 0), но titleForHeaderInSection шел за панелью инструментов 

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

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

4
grep

Обратите внимание, что принятый ответ потерпит крах, если в табличном представлении нет данных. И добавление его в 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)];
}
3
user3246173

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

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

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

Другие ответы на этот вопрос либо вообще не работали для меня, либо имели странное поведение, когда 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 (имеется в виду, что позиция ycontentOffset, или позиция прокрутки 0). Если это так, он просто прокручивается вниз по высоте панели поиска. Если searchBar не виден (например, большой список элементов в tableView), он не будет пытаться прокручивать tableView, так как это приведет к путанице в позиционировании при возврате из вложенной позиции.

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

1
kbpontius

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

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

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

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

self.tableView.selectRowAtIndexPath (firstIndexPath, animated: false, scrollPosition: .Top)

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

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

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

Сначала определите переменную 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
        }
1
drdrdrdr

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

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

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

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

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

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

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

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

1
Chilly Zhong

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

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

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

1
LightMan

У меня была похожая проблема. И единственный способ решить эту проблему - использовать наблюдатель значения ключа для свойства 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"];
}
0
slobodans

Для Свифта:

Просто сделайте табличное представление y смещением, которое должно быть как высота панели поиска.

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

Свифт 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)
}
0
John

Я попытался установить смещение содержимого и 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)
    }
}

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

0
Abdur Rahman

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

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

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

0
fujianjin6471