Странный пробел в контроллере поиска iOS 13

При запуске приложения на iOS 13 beta 6 с использованием Xcode 11 beta 5 я сталкиваюсь со странным пробелом при представлении контроллера представления результатов поиска:

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

Вот немного того, как это устроено:

let searchResultsController = BLSearchResultsController()

let ret = UISearchController(searchResultsController: searchResultsController)
ret.searchResultsUpdater = self
ret.delegate = self
ret.searchBar.delegate = self;
ret.searchBar.autocapitalizationType = .none
ret.searchBar.placeholder = NSLocalizedString("SearchMsg", comment: "")
        ret.searchBar.enablesReturnKeyAutomatically = true

if #available(iOS 13.0, *) {
    ret.searchBar.showsScopeBar = false
    ret.searchBar.backgroundColor = .white

    let searchTextField = ret.searchBar.searchTextField
    searchTextField.font = UIFont.tuttiRegularFont(16)
    searchTextField.accessibilityIdentifier = "Main Search Field"
    if let searchImageView = searchTextField.leftView as? UIImageView {
        searchImageView.image = UIImage(named: "home-search-icon")
     }
}

Контроллер поиска результатов представляет собой обычный UITableViewController и просто добавляется к navigationItem.searchController. Там нет причудливого кода презентации. При сборке последнего живого Xcode и запуске на устройстве iOS 11/12 этой проблемы нет, что наводит меня на мысль, что некоторые базовые изменения iOS 13 могут вызывать этот сбой.

При отладке иерархии представлений кажется, что контроллер представления результатов не достигает верхней части перемещенной панели поиска.

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

Кто-нибудь сталкивался с этой проблемой и успешно решил ее?


person UrosMi    schedule 16.08.2019    source источник
comment
Возможный дубликат панели поиска UISearchController в заголовке таблицы. разрыв строки состояния   -  person mmika1000    schedule 16.08.2019
comment
к сожалению, у меня нет элементов управления сегментами или чего-то еще. Мой контроллер поиска только что встроен в navigationItem.searchController. Я думаю, что это связано с некоторыми базовыми изменениями iOS 13, поскольку этого не происходит при работе с текущим Xcode с текущими версиями iOS.   -  person UrosMi    schedule 16.08.2019
comment
все еще дважды проверял, и ни один из этих ответов не помог   -  person UrosMi    schedule 16.08.2019
comment
У меня тоже есть эта проблема, и я не уверен, что ее вызывает.   -  person SlashDevSlashGnoll    schedule 26.08.2019
comment
У меня та же проблема, даже в существующей версии, созданной с помощью Xcode 10.3 на iOS 13.   -  person Igor Kulman    schedule 05.09.2019
comment
Извините, что добавил меня тоже, но... я тоже.   -  person Nostradamus    schedule 17.09.2019
comment
Эй, чувак, ты нашел решение   -  person Swift Sharp    schedule 03.10.2019
comment
Ничего хакерского @SwiftSharp... на данный момент удаление UISearchController выглядит единственным хорошим решением   -  person UrosMi    schedule 07.10.2019


Ответы (12)


Параметр

extendedLayoutIncludesOpaqueBars = true

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

person DrS    schedule 29.08.2019

У нас была та же проблема, и решение состояло в том, чтобы установить Under Opaque Bars (поскольку мы используем непрозрачные полосы) Под непрозрачными полосами

У нас уже были проверены Top и Bottom, добавление третьего переместило контроллер результатов поиска в нужное место.

person TodayMorning    schedule 29.08.2019
comment
да, я пробовал это, но не повезло... Пришлось делать это через код, так как этот проект использует .xibs, поэтому я сделал searchResultsController.extendedLayoutIncludesOpaqueBars = true searchResultsController.edgesForExtendedLayout = .all - person UrosMi; 29.08.2019
comment
Мне пришлось установить его на контроллере просмотра, на котором размещен контроллер поиска, а не на самом контроллере поиска. - person Hons; 23.09.2019
comment
Это оставило странный пробел над моей панелью навигации. Мне пришлось использовать ответ @mirkobraic. Как некрасиво, как кажется - person PJayRushton; 31.10.2019

Для меня проблема заключалась в том, что UISearchController не обновлял свой фрейм, когда панель поиска перемещалась вверх. Я исправил это, установив фрейм UISearchController в фрейм контроллера представления.

extension UISearchController {
    open override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if let presentingVC = self.presentingViewController {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                self.view.frame = presentingVC.view.frame
            }
        }
    }
}

В viewWillAppear анимация строки поиска не запустилась, поэтому приходится ждать доли секунды. Когда начинается анимация, кадр представления VC устанавливается на правильное значение, а затем вы можете обновить кадр вашего UISearchController. Решение - хак, но оно отлично работает для меня.

person mirkobraic    schedule 24.10.2019
comment
Я буквально пропустил этот ответ и попробовал все остальные. Наконец вернулся к этому через 2 часа как последнее усилие. К сожалению, это сработало. Куда катится мир?! - person PJayRushton; 31.10.2019

Наконец-то пройти через трудности. Просто чтобы первый контроллер содержал UISearchController, чтобы иметь полупрозрачную панель навигации. Работа для меня отлично!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationController?.navigationBar.isTranslucent = true
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationController?.navigationBar.isTranslucent = false
    }
person Raydemo    schedule 23.09.2019
comment
Здесь важную роль играет установка isTrunslucent в истинное значение, чтобы панель поиска контроллера поиска не была полностью черной. Но любая идея, почему это нужно установить. Это немного нелогично, почему настройка панели навигации на полупрозрачность делает ее не черной (прозрачной?) - person Michał Ziobro; 24.09.2019

extendedLayoutIncludesOpaqueBars = true действительно помогло в некоторой степени.

Вместе с этим мне пришлось обновить

navigationController?.navigationBar.prefersLargeTitles = false

когда мы начинаем поиск и возвращаем его к true, когда панель поиска закрывается.

person Baby Groot    schedule 11.09.2019
comment
сделал что-то подобное :( - person UrosMi; 23.09.2019

К вашему сведению, я отправил отчет об ошибке в Apple — согласно презентации WWDC, в которой описывается новая -написал SearchController и некоторые другие обновления пользовательского интерфейса, похоже, что архитектура SearchController была переписана с нуля. Я не могу поверить, что этот разрыв, который мы наблюдаем, является ожидаемым поведением – я потратил большую часть двух дней, пытаясь преодолеть это, и я не беспокоит дальше - мое приложение в магазине приложений - это бесплатное приложение, у которого есть несколько пользователей, и я не мог уделять время отслеживанию изменений/поведения в API в течение бета-периода, я несколько устал от Apple, делающей это вещи ежегодно.

person Nostradamus    schedule 22.09.2019

  1. Как упоминалось в приведенных выше ответах, установите флаг «Расширить края под непрозрачными полосами» как «Вкл.» для UIViewController, который представляет результаты поиска. Для меня этого было недостаточно, потому что я использую НЕ полупрозрачную панель навигации.
  2. Поэтому я добавил следующую реализацию для методов UISearchControllerDelegate:
    - (void)willPresentSearchController:(UISearchController *)searchController
    {
        if (@available(iOS 13.0, *))
        {
            self.navigationController.navigationBar.translucent = YES;
        }
    }

    - (void)willDismissSearchController:(UISearchController *)searchController
    {
        if (@available(iOS 13.0, *))
        {
            self.navigationController.navigationBar.translucent = NO;
        }
    }
person Alexander Survillo    schedule 09.10.2019
comment
Его stackoverflow.com/questions/58427943/ Можете ли вы проверить это, у меня такая же проблема, но ни одно из решений не работает для меня - person Yogesh Patel; 25.10.2019

Использование .asyncAfter(deadline: .now() + 0.1) вызовет сбой в пользовательском интерфейсе. Чтобы избавиться от этого, избавьтесь от крайнего срока! Достаточно использовать DispatchQueue.main.async.

extension UISearchController {
    open override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if let presentingVC = self.presentingViewController {
            DispatchQueue.main.async {
                self.view.frame = presentingVC.view.frame
            }
        }
    }
}
person Tiziano Coroneo    schedule 31.10.2019

Самое простое решение - установить это в вашем searchResultsController:

searchResultsController.edgesForExtendedLayout = UIRectEdgeNone;
person Bms270    schedule 04.06.2020

Вы должны установить для своего navigationBar.standardAppearance объект UINavigationBarAppearance, описывающий белый фон.

if #available(iOS 13.0, *) {
        let appearance = UINavigationBarAppearance()
        appearance.backgroundColor = .white
        self.navigationController?.navigationBar.standardAppearance = appearance
}
person user3187971    schedule 18.09.2019

В конце концов я решил эту проблему, заменив UISearchController на простой (r) UISearchBar.

Возможно, это не тот ответ, который вы хотели услышать, но UISsearchController уже был в беспорядке на iOS12, тот же код на iOS13 работает, но дает ужасные артефакты пользовательского интерфейса. Например, исчезновение или перекрытие панели поиска с заголовком, пробел между панелью поиска и первым элементом таблицы или скрытие первого элемента списка под кнопками области... Все разные проблемы между iOS12 и 13, но они никогда не выглядят хорошо.

Итак, в целом я потратил 6 часов, пытаясь починить контроллер поиска, потерпел неудачу, а затем потратил 30 минут на миграцию на панель поиска.

Я добавил UISearchBar, просто используя Interface Builder в Xcode10.3. Для рефакторинга в основном мне приходилось просто заменять searchController.searchBar.xx на searchBar.xx . Основное усилие заключалось в повторной реализации UISeachBarDelegates. Просто чтобы показывать только кнопки области и кнопку отмены, пока пользователь выполняет поиск, а затем удалять их. Код ниже дает хороший обзор того, что я сделал:

class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate {

  var fetchedItemsController: NSFetchedResultsController<Item>! = NSFetchedResultsController()

  @IBOutlet weak var searchBar: UISearchBar! //hooked up to IB
  //GONE IS: let searchController = UISearchController(searchResultsController: nil)


  override func viewDidLoad() {
    super.viewDidLoad()

    initializeFetchedResultsControllerForItems()

    //Enable search controller
    searchBar.scopeButtonTitles = [NSLocalizedString("Name", comment: ""),
                                   NSLocalizedString("Birthdate", comment: ""),
                                   NSLocalizedString("Employer", comment: "")    ]
    searchBar.placeholder = NSLocalizedString("Search", comment: "")
    searchBar.delegate = self
    searchBar.showsScopeBar = false
    searchBar.showsCancelButton = false

    tableView.contentInsetAdjustmentBehavior = .automatic
    self.tableView.tableHeaderView = searchBar //add the searchbar as tableheader view

    self.initializeFetchedResultsControllerForItems()

  }

  // MARK: - Data loading from CoreData
  private func initializeFetchedResultsControllerForItems(searchText: String = "", scopeIndex: Int = 0) {
    //print("FETCH RESULTS WITH FILTER: \(searchText) en SCOPE: \(scopeIndex)")
    //Do whatever searches you need to do to update the FetchedResultsController
    //..
    self.tableView.reloadData()
  }
}

extension MasterViewController: UISearchBarDelegate {  //the delegates for the searchbar
  func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
    searchBar.showsScopeBar = true  //show the scopebar when users adds text to searchbar
    searchBar.showsCancelButton = true //also show the cancel button
    searchBar.sizeToFit()
    self.tableView.reloadData() //since the scopebar is there, the table needs to move a bit down

  }
  func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
  }
  func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    initializeFetchedResultsControllerForItems(searchText: searchBar.text!, scopeIndex: searchBar.selectedScopeButtonIndex)
  }
  func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
    switch (selectedScope) {
    case 0: searchBar.placeholder = NSLocalizedString("Seach on name", comment: "")
    case 1: searchBar.placeholder = NSLocalizedString("Search on birthdate", comment: "")
    case 2: searchBar.placeholder = NSLocalizedString("Search on employer", comment: "")
    default: searchBar.placeholder = NSLocalizedString("Search", comment: "")

    searchBar.showsScopeBar = true
    searchBar.sizeToFit()
    }

    initializeFetchedResultsControllerForItems(searchText: searchBar.text!, scopeIndex: selectedScope)
  }
  func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    searchBar.placeholder = NSLocalizedString("Search", comment: "")
    searchBar.showsScopeBar = false
    searchBar.showsCancelButton = false
    searchBar.endEditing(true)
    searchBar.text = ""
    searchBar.sizeToFit()
    initializeFetchedResultsControllerForItems(searchText: searchBar.text!, scopeIndex: searchBar.selectedScopeButtonIndex)
  }
}
person Rodge    schedule 01.10.2019
comment
Да, я также думаю о рефакторинге uisearchviewcontroller. - person UrosMi; 01.10.2019

Просто приношу свое решение. В моем случае:

edgesForExtendedLayout = .all

на UIViewController, который содержит UISearchController.

//MARK: - Properties
var presenter: ExplorePresenting?
var searchController: UISearchController?
var searchUpdater: SearchUpdating?


//MARK: - Lifecycle methods
public override func viewDidLoad() {
    super.viewDidLoad()

    headerTitle = "explore".localised
    tableView.allowsSelection = false
    registerCell(cellClass: ExploreTableViewCell.self, with: tableView)

    if let searchController = searchController {

        searchController.searchBar.delegate = self
        searchController.searchResultsUpdater = self
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.placeholder = "explore_search_placeholder".localised

        definesPresentationContext = true
        navigationItem.hidesSearchBarWhenScrolling = false
        navigationItem.searchController = searchController
        edgesForExtendedLayout = .all

    }

    presenter?.viewReady()

}
person Reimond Hill    schedule 10.10.2019