UISearchController 的 UISearchBar 在活动时移出屏幕

UISearchBar of UISearchController moves off screen when active

我需要在 UISearchBar 上面 一个 UITableView (即搜索栏不是 table 视图的一部分) ,我发现当搜索栏被激活时,它会移出屏幕。

我进行了大量搜索,但找不到解决方案,存在“屏幕外搜索栏”问题,但他们正在将搜索栏添加到 table 的 header 视图并进行调整definesPresentationContext 等属性修复了它。

我的视图层次结构:

VC的观点 |— 顶视图 |— 分段控制 |— 搜索栏 |— table 查看

看起来 UISearchController 期望搜索栏位于 table 视图内,并且总是移动 table 视图,以便搜索栏移动到屏幕的最顶部。

有人遇到同样的问题并找到了解决方案吗?

非常感谢!

我认为将 searchBar 放在 tableView 中不是强制性的。前段时间我遇到了同样的问题。您需要做的就是设置适当的自动布局约束。将 searchView 的前导和尾随调整为与 tableView 的前导和尾对齐。同时从约束中释放边距 属性。希望对您有所帮助。

经过几次尝试,我发现原因是当 UISearchBar 被激活时,UISearchController 将其从您的视图中删除并使用 [=16] 将其放在自己的视图中=] 用于显示结果的视图,因为我对搜索栏使用了自动布局,通过删除它,一些约束被搞砸了。所以我的解决方案是不对 UISearchController.

中的 UISearchBar 使用自动布局

更新

经过进一步测试后,我决定只实现 UISearchBar 委托并停止使用 UISearchController,因为我只是重复使用我的 UICollectionView 来获取结果。找到一个 great guide on how three different methods 来实现 SearchBar。

边缘案例 #1

TLDR

Enable clips to bounds on the containing view. Or if you have a collection view cell that has a user-generated content view, enable clips to bounds on that content view.

详情:

另一个非常重要的事实是,您可以将搜索栏嵌入到容器视图中。如果容器视图没有启用边界剪辑,这可能会导致问题。这成为问题的其他示例是 UICollectionViewCells 中用户生成的内容视图。比较 UITableViewCell 自动生成的内容视图上的设置以观察差异。

Summary

A Boolean value that determines whether subviews are confined to the bounds of the view. Declaration

var clipsToBounds: Bool { get set } Discussion

Setting this value to true causes subviews to be clipped to the bounds of the receiver. If set to false, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. The default value is false.

Swift4.x解决方案

在我的例子中,这发生在 UICollectionView 和 UIStackView 内部。在 searchBar 快速帮助中注意到以下信息后,我能够将 searchBar 保持在原位。

Summary

The search bar to install in your interface. Declaration

var searchBar: UISearchBar { get } Discussion

Before presenting your searchable content, install the search bar in this property somewhere into your view controller’s interface. The search bar becomes the starting point for searching your contents. Interactions with the search bar are handled automatically by the UISearchController object, which notifies the object in the searchResultsUpdater property whenever the search information changes. To use a custom subclass of UISearchBar, subclass UISearchController and implement this property to return your custom search bar.

之后,我通过执行以下操作成功解决了问题:

let searchController = UISearchController(searchResultsController: nil)
var searchBar:UISearchBar!

稍后我将 searchController 中的 searchBar 分配给 UIViewController 中的 searchBar...

顺便说一句 - 我将我的 searchBar 嵌入到一个容器 UIView 中,该容器具有我需要的所有约束以将其保留在适当的位置。

func setupSearchController<T:UIViewController>(delegate vc:T) where T: UISearchResultsUpdating, T:UISearchBarDelegate {
    searchBar = searchController.searchBar //this is the key
    searchController.searchResultsUpdater = vc
    searchController.obscuresBackgroundDuringPresentation = false
    searchController.searchBar.placeholder = "Search".localized()
    searchController.dimsBackgroundDuringPresentation = false
    searchController.searchBar.delegate = vc
    searchController.searchBar.showsCancelButton = true
    definesPresentationContext = true
    self.searchMenu.addSubview(searchBar) 
    //searchMenu is a constrained UIView in my hierarchy
}

// Swift 5

// 如果您使用的是 UISearch 控制器,则只需在下面添加一行 viewDidLoad() 它将解决问题。

override func viewDidLoad() {
     super.viewDidLoad()

     // fixes the search moving to next screen when its active
     self.definesPresentationContext = true
}

如果您选择在没有 UISearchController 的情况下使用 UISearchBar,我发现将 UISearchBar 保持在其初始范围内要容易得多,这里是代码模板:

final class MyUIViewController: UIViewController {
    // MARK: Properties
    private let tableView = UITableView()
    private let searchBar = UISearchBar()
    ...

    // MARK: View Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

        ...

        searchBar.delegate = self
        searchBar.sizeToFit()
        
        tableView.tableHeaderView = searchBar
    }
}

extension MyUIVewController: UISearchBarDelegate {

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        ... // Your code filtering tableView dataSource goes here

        tableView.reloadData()
    }
    
}