Программно отображать панель поиска UISearchController

Примечание 1. Этот вопрос относится к добавлению панели поиска UISearchController за пределы обновляемого табличного представления, а НЕ в качестве заголовка табличного представления.

Примечание 2. Путем проб и ошибок я нашел решение. См. мой ответ ниже.

Я новичок в разработке iOS и изо всех сил пытаюсь работать с классом UISearchController. У меня есть контроллер представления, и в представлении моего контроллера представления я планирую иметь панель поиска над табличным представлением. Я хотел бы, чтобы панель поиска была связана с UISearchController. Поскольку построитель интерфейса не поставляется с UISearchController, я добавляю контроллер программно. После создания экземпляра UISearchController я попытался программно добавить панель поиска контроллера поиска в свое представление, но безуспешно. Я попытался установить рамку панели поиска и задать для нее ограничения автомакета, но ни один из подходов мне не помог (т.е. когда я запускаю приложение, ничего не появляется). Вот последний код, который я пробовал:

    let searchController = UISearchController(searchResultsController: nil)

    // Set the search bar's frame
    searchController.searchBar.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 50)

    // Constraint to pin the search bar to the top of the view
    let topConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
    searchController.searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)

    self.view.addSubview(searchController.searchBar)

    self.view.addConstraint(topConstraint)

Любая помощь будет принята с благодарностью! Благодарю вас!

РЕДАКТИРОВАТЬ: Использование только одного из вариантов настройки рамки панели поиска или установки ограничений автомакета (в отличие от комбинации того и другого, как я изначально пытался) сначала работает, но после нажатия на панель поиска у вас будут проблемы, как указал Дуайт. Я оставил код для этих случаев на случай, если будет полезно сравнить с тем, что у вас есть в настоящее время, но для рабочего решения см. Мой ответ ниже.

Использование ограничений автомакета:

    let searchController = UISearchController(searchResultsController: nil)

    let topConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: (statusBarHeight + navigationBarHeight!))
    let leftConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0)
    let rightConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0)
    let heightConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 44)
    searchController.searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)

    searchController.searchBar.addConstraint(heightConstraint)

    self.view.addSubview(searchController.searchBar)

    self.view.addConstraints([topConstraint, leftConstraint, rightConstraint])

Я установил константу topConstraint на высоту строки состояния плюс высоту панели навигации, поскольку мой контроллер представления встроен в контроллер навигации.

Регулировка рамки:

    let searchController = UISearchController(searchResultsController: nil)

    searchController.searchBar.frame = CGRect(x: 0, y: (statusBarHeight + navigationBarHeight!), width: self.view.frame.size.width, height: 44)

    self.view.addSubview(searchController.searchBar)

person kcstricks    schedule 08.07.2015    source источник
comment
попробуйте эту link1, link2 может вам помочь   -  person Anbu.Karthik    schedule 08.07.2015
comment
@Anbu.Karthik спасибо за ссылки! Первый, кажется, делает именно то, что я хочу, с немного большим участием конструктора интерфейса, поэтому я рассмотрю его поближе. Во-вторых, я использую UISearchDisplayController, который, я считаю, устарел с iOS 8.   -  person kcstricks    schedule 08.07.2015
comment
Я столкнулся с той же проблемой, что и вы, однако у меня возникают проблемы после того, как пользователь нажимает на строку поиска. С опцией фрейма панель поиска выдвигается из представления, а табличное представление отображается, но не позиционируется правильно. С параметром ограничений приложение аварийно завершает работу с ошибкой «Иерархия представлений не подготовлена ​​для ограничения: ошибка после нажатия». Вы тоже столкнулись с этими проблемами?   -  person Dwight    schedule 18.08.2015
comment
@ Дуайт - спасибо за это. Вы правы - ни одно из решений в редактировании 1 не работает. Я подтвердил те же проблемы, что и у вас. Пожалуйста, смотрите редактирование 2! Кажется, это работает хорошо для меня. Дайте мне знать, если это работает для вас!   -  person kcstricks    schedule 18.08.2015
comment
@kcstricks - вау, большое спасибо за ответ, я думал, что это будет безнадежное дело. Edit 2 работает блестяще, хорошая работа! Такая боль просто получить функциональность UISearchDisplayController с UISearchController! Вы обязательно должны опубликовать edit 2 в качестве ответа на этот вопрос, чтобы помочь другим. Спасибо еще раз!   -  person Dwight    schedule 19.08.2015
comment
@Dwight - Нет проблем, я рад, что это сработало для вас!   -  person kcstricks    schedule 19.08.2015


Ответы (2)


После еще нескольких проб и ошибок у меня есть следующее рабочее решение:

  1. Откройте Main.storyboard и добавьте в свой контроллер представления UIView с высотой 44 (высота UISearchBar по умолчанию) и UITableView. Установите ограничения автомакета, чтобы UIView был прикреплен к двум сторонам и к верхней направляющей макета (использование верхней направляющей макета гарантирует, что это будет работать независимо от того, встроен ли ваш контроллер представления в контроллер навигации), а табличное представление закреплено к две стороны, нижняя направляющая макета и ее верхняя часть, прикрепленная к нижней части UIView.
  2. Подключите UIView и UITableView как IBOutlets в вашем ViewController.swift. В своем проекте я назвал их topView и tableView.
  3. Объявите контроллер поиска вверху вашего ViewController.swift: var searchController: UISearchController!
  4. Затем в viewDidLoad() вам понадобится:

    // Initialize and set up the search controller
    self.searchController = UISearchController(searchResultsController: nil)
    self.searchController.searchResultsUpdater = self
    self.searchController.dimsBackgroundDuringPresentation = false // Optional
    self.searchController.searchBar.delegate = self
    
    // Add the search bar as a subview of the UIView you added above the table view
    self.topView.addSubview(self.searchController.searchBar)
    // Call sizeToFit() on the search bar so it fits nicely in the UIView
    self.searchController.searchBar.sizeToFit()
    // For some reason, the search bar will extend outside the view to the left after calling sizeToFit. This next line corrects this.
    self.searchController.searchBar.frame.size.width = self.view.frame.size.width
    

Это должно быть так! Конечно, вам нужно будет сделать свой контроллер представления UITableViewDatasource, UITableViewDelegate, UISearchBarDelegate, UISearchControllerDelegate и UISearchResultsUpdating, а также позаботиться обо всех необходимых методах делегата, но что касается панели поиска, это сработало для меня. Пожалуйста, прокомментируйте, если у вас есть какие-либо проблемы.

person kcstricks    schedule 19.08.2015
comment
// По какой-то причине панель поиска выходит за пределы представления влево. Это происходит потому, что в viewDidLoad() кадры представлений еще не рассчитаны правильно, хотя ваша панель поиска получает неправильный кадр, который намного больше, чем должен быть. если вы хотите сделать все правильно, сделайте sizeToFit() в своем viewDidAppear или после того, как ваше представление закончило макетирование. - person Fawkes; 29.09.2015
comment
@Fawkes - спасибо за вклад. У меня есть к вам быстрый дополнительный вопрос: если это так, и рамка представления еще не вычислена правильно, когда я вызываю sizeToFit(), то знаете ли вы, почему это сработало, чтобы установить ширину searchBar в ширину представления о следующей строке кода? Если в этот момент рамка представления все еще не рассчитана должным образом, не должно ли вышеописанное работать? - person kcstricks; 29.09.2015
comment
К сожалению, не могу найти что-то очень подробное о sizeToFit(), но, как написано, -> Изменяет размер и перемещает представление получателя, поэтому оно просто заключает в себя свои подпредставления. Это, вероятно, означает, что принудительный расчет кадра происходит, как в случае layoutIfNeeded(), поэтому после вызова sizeToFit() вы получаете представления, для которых кадр был рассчитан до того, как это произошло бы обычно, как после viewDidLayoutSubviews или viewDidAppear. - person Fawkes; 29.09.2015
comment
@Fawkes - спасибо за внимание. Это будет полезно иметь в виду в следующий раз, когда я буду возиться с фреймами во время загрузки представления :) - person kcstricks; 29.09.2015
comment
Я не думаю, что это работает, если вы пытаетесь добавить панель поиска в представление, которое не является полной шириной контроллера представления. Мне кажется, что панель поиска не будет иметь ширину меньше ширины контроллера представления. - person SAHM; 13.02.2017
comment
Когда я делаю это и нажимаю на строку поиска, строка поиска прыгает вниз примерно на 80 пунктов. Когда я отменяю поиск, он возвращается туда, где был. Кто-нибудь знает, как это исправить? - person coolcool1994; 12.11.2017
comment
Привет, @coolcool1994! Я не просматривал этот код годами и больше не работаю над приложением. Что-то определенно могло измениться за это время. Вы поняли это? - person kcstricks; 15.11.2017
comment
@ coolcool1994 Привет, тебе удалось исправить прыжки строки поиска вниз, как проблема с 80 баллами? Я столкнулся с той же проблемой в iOS 12. - person Keyhan Kamangar; 10.11.2020

попробуй это:

        let searchController = UISearchController(searchResultsController: nil).searchBar

        // Set the search bar's frame
        searchController.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 50)

        // Constraint to pin the search bar to the top of the view
        let topConstraint = NSLayoutConstraint(item: searchController, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
//        searchController.setTranslatesAutoresizingMaskIntoConstraints(false)

        self.view.addSubview(searchController)
//        self.presentViewController(searchController, animated: true, completion: nil)

        self.view.addConstraint(topConstraint)

или вы можете просто сделать это:

    searchController.searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)   
->  searchController.searchBar.setTranslatesAutoresizingMaskIntoConstraints(true)
person A BLUE    schedule 08.07.2015
comment
Спасибо за вашу помощь! Меня немного смущает ваше первое предложение, потому что кажется, что это просто добавляет панель поиска, а не панель поиска, связанную с контроллером поиска. Пожалуйста, поправьте меня, если я ошибаюсь. Что касается вашего второго предложения, установка для setTranslatesAutoResizingMaskIntoConstraints значения true работает для отображения панели поиска, если вы указали ее рамку. Однако я считаю, что этот флаг установлен по умолчанию, поэтому я думаю, что вы можете просто указать фрейм и оставить эту строку, как я сделал в РЕДАКТИРОВАТЬ 1 моего поста. - person kcstricks; 08.07.2015