web-dev-qa-db-fra.com

Lacune étrange du contrôleur de recherche iOS 13

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:

enter image description here

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?

28
UrosMi

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

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

}
0
Reimond Hill

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
}
0
user3187971

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
            }
        }
    }
}
0
Tiziano Coroneo