【问题标题】:iOS 13 strange search controller gapiOS 13 奇怪的搜索控制器间隙
【发布时间】:2019-12-22 14:54:00
【问题描述】:

在 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。没有花哨的演示代码。在最新的 live Xcode 上构建并在 iOS 11/12 设备上运行时,此问题不存在,这使我相信一些底层 iOS 13 更改可能会导致此故障。

在调试视图层次结构时,结果视图控制器似乎没有到达移动的搜索栏的顶部。

我尝试摆弄modalPresentationModes 试图排除可能是演示文稿更改的可能性,但没有运气。

有没有人遇到过这个问题并幸运地解决了它?

【问题讨论】:

  • 不幸的是,我没有任何段控制或任何东西。我的搜索控制器刚刚嵌入到navigationItem.searchController。我认为这是在一些底层 iOS 13 更改的背景下,因为在当前 Xcode 和当前 iOS 版本上运行时不会发生这种情况
  • 仍然仔细检查,这些答案都没有帮助
  • 我也遇到了这个问题,不知道是什么原因造成的。
  • 我也有同样的问题,即使在 iOS 13 上使用 Xcode 10.3 构建的现有版本中也是如此

标签: swift xcode ios13


【解决方案1】:

设置

extendedLayoutIncludesOpaqueBars = true

在用于显示搜索结果的UIViewController 中,为我解决了这个问题。

【讨论】:

    【解决方案2】:

    我们遇到了同样的问题,解决方案是设置在不透明条下(因为我们使用不透明条)

    我们已经检查了顶部和底部,添加第三个将搜索结果控制器移动到正确的位置。

    【讨论】:

    • 是的,我试过了,但没有运气......因为这个项目使用.xibs所以我做了searchResultsController.extendedLayoutIncludesOpaqueBars = true searchResultsController.edgesForExtendedLayout = .all
    • 我必须在托管 searchcontroller 的 viewcontroller 上设置它,而不是在 searchcontroller 本身上
    • 这在我的导航栏上方留下了一个奇怪的空白。我不得不使用@mirkobraic 的答案。看起来很丑
    【解决方案3】:

    对我来说,问题是当搜索栏向上移动时 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 的帧。解决方案是一个hack,但对我来说效果很好。

    【讨论】:

    • 我确实跳过了这个答案并尝试了其他所有答案。终于在 2 小时后回到这作为最后的努力。不幸的是,它奏效了。世界会变成什么样子?!
    【解决方案4】:

    终于熬过了难关。只是为了让第一个控制器包含 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
        }
    

    【讨论】:

    • 这里将 isTrunslucent 设置为真值对于不让搜索控制器的搜索栏全黑起到重要作用。但是知道为什么需要设置它。这有点违反直觉,为什么将导航栏设置为半透明会使其不是黑色(透明?)
    【解决方案5】:

    extendedLayoutIncludesOpaqueBars = true 确实在一定程度上有所帮助。

    除此之外,我不得不更新

    navigationController?.navigationBar.prefersLargeTitles = false

    当我们开始搜索并在搜索栏被关闭时将其设置回true

    【讨论】:

    • 现在做了类似的事情:(
    【解决方案6】:

    仅供参考,我向苹果提交了一份错误报告 - 根据the WWDC presentation that describes the newly re-written SearchController and some other UI updates,听起来 SearchController 的架构已经从头开始重写。 我无法相信我们所看到的这种差距是预期的行为 - 我浪费了两天的大部分时间试图超越这一点,但我不是打扰了 - 我的应用商店应用程序是一个免费应用程序,有很多用户,我无法在测试期间花时间跟踪 API 的变化/行为,我有点厌倦了苹果这样做每年的事情。

    【讨论】:

      【解决方案7】:
      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;
              }
          }
      

      【讨论】:

      【解决方案8】:

      使用 .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
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案9】:

        最简单的解决方案是在您的 searchResultsController 上设置:

        searchResultsController.edgesForExtendedLayout = UIRectEdgeNone;
        

        【讨论】:

          【解决方案10】:

          您必须将您的 navigationBar.standardAppearance 设置为描述白色背景的 UINavigationBarAppearance 对象。

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

          【讨论】:

            【解决方案11】:

            我终于解决了这个问题,用一个简单的(r) UISearchBar 替换了 UISearchController。

            也许不是你想听到的答案,但 UISsearchController 在 iOS12 上已经是一团糟,iOS13 上的相同代码可以工作,但会产生可怕的 UI 伪影。就像搜索栏与标题消失或重叠,搜索栏和表格的第一个元素之间的空白,或者将第一个列表项隐藏在范围按钮下,...... iOS12 和 13 之间的所有不同问题,但从来都不是很好。

            所以总的来说,我花了 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)
              }
            }
            

            【讨论】:

            • 是的,我也在考虑重构 uisearchviewcontroller
            【解决方案12】:

            只是带来我的解决方案。就我而言:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-09-30
              • 1970-01-01
              • 2022-07-07
              • 1970-01-01
              • 2012-03-20
              相关资源
              最近更新 更多