IOS 13ベータ6でアプリを実行しているときに、Xcode 11ベータ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
をいじくり回して、プレゼンテーションへの変更が原因である可能性を排除しようとしましたが、そこに運がありませんでした。
誰かがこの問題に遭遇し、幸運にそれを修正しましたか?
最後に、UISearchControllerをsimple(r)UISearchBarに置き換えることでこれを解決しました。
多分あなたが聞きたかった答えではないかもしれませんが、UISsearchControllerはすでにiOS12では混乱しています。iOS13の同じコードは機能しますが、恐ろしいUIアーティファクトを与えます。検索バーをヘッダーと重ねて表示しない、またはオーバーラップするように、検索バーとテーブルの最初の要素の間に空白を入れたり、スコープボタンの下に最初のリストアイテムを非表示にしたりします。
そのため、全体として、検索コントローラーを修正するために6時間を費やし、失敗してから、30分かけて検索バーに移行しました。
Xcode10.3のInterface Builderを使用してUISearchBarを追加しました。リファクタリングでは、ほとんどの場合、単純に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)
}
}
ちょうど私のソリューションをもたらします。私の場合:
edgesForExtendedLayout = .all
uISearchControllerを含むUIViewControllerで動作しました。
//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()
}
NavigationBar.standardAppearanceを、白い背景を表すUINavigationBarAppearanceオブジェクトに設定する必要があります。
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = .white
self.navigationController?.navigationBar.standardAppearance = appearance
}
.asyncAfter(deadline: .now() + 0.1)
を使用すると、UIでグリッチが発生します。それを取り除くために、締め切りを取り除く! 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
}
}
}
}