Lors de l'exécution de l'application sur iOS 13 bêta 6, en utilisant Xcode 11 bêta 5, je rencontre l'étrange écart lors de la présentation du contrôleur d'affichage des résultats de recherche:
Voici un peu comment cela est configuré:
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")
}
}
Le contrôleur de recherche de résultats est un UITableViewController
normal et vient d'être ajouté au navigationItem.searchController
. Il n'y a pas de code de présentation sophistiqué. Lors de la construction du dernier Xcode en direct et de l'exécution sur l'appareil iOS 11/12, ce problème n'est pas présent, ce qui m'amène à croire que certains changements sous-jacents d'iOS 13 pourraient être à l'origine de ce problème.
Lors du débogage de la hiérarchie des vues, il semble que le contrôleur de vue des résultats n'atteigne pas le haut de la barre de recherche déplacée.
J'ai essayé de jouer avec le modalPresentationModes
en essayant d'exclure la possibilité que les modifications de la présentation puissent en être la cause, je n'ai pas eu de chance.
Quelqu'un a-t-il rencontré ce problème et eu de la chance de le résoudre?
J'ai finalement résolu cela en remplaçant le UISearchController par un simple (r) UISearchBar.
Peut-être pas la réponse que vous vouliez entendre, mais l'UISsearchController était déjà un gâchis sur iOS12, le même code sur iOS13 fonctionne mais donne d'horribles artefacts d'interface utilisateur. Comme disparaître ou chevaucher la barre de recherche avec l'en-tête, un espace blanc entre la barre de recherche et le premier élément du tableau, ou masquer le premier élément de liste sous les boutons de portée, ... Tous les différents problèmes entre iOS12 et 13, mais jamais bien.
Donc, dans l'ensemble, j'ai passé 6 heures à essayer de réparer le contrôleur de recherche, j'ai échoué, puis j'ai passé 30 minutes à migrer vers la barre de recherche.
J'ai ajouté UISearchBar en utilisant simplement Interface Builder dans Xcode10.3. Pour le refactoring, j'ai surtout dû simplement remplacer searchController.searchBar .xx par searchBar.xx. L'effort principal consistait à réimplémenter UISeachBarDelegates. Juste pour n'afficher que les boutons de portée et le bouton Annuler pendant que l'utilisateur recherche et les supprimer ensuite. Le code ci-dessous donne un bon aperçu de ce que j'ai fait:
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)
}
}
J'apporte juste ma solution. Dans mon cas:
edgesForExtendedLayout = .all
sur le UIViewController qui contient le UISearchController travaillé.
//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()
}
Vous devez définir votre navigation Bar.standardAppearance sur un objet UINavigationBar Appearance qui décrit un fond blanc.
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = .white
self.navigationController?.navigationBar.standardAppearance = appearance
}
L'utilisation de .asyncAfter(deadline: .now() + 0.1)
provoquera un problème dans l'interface utilisateur. Pour vous en débarrasser, débarrassez-vous du délai! En utilisant DispatchQueue.main.async
est assez.
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
}
}
}
}