You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让UISearchBar始终可见?解决CollectionView不可滚动时隐藏问题

问题描述

我通过以下代码设置了UISearchBar:

// https://www.raywenderlich.com/4363809-uisearchcontroller-tutorial-getting-started
// https://developer.apple.com/documentation/uikit/view_controllers/displaying_searchable_content_by_using_a_search_controller
private lazy var searchController: UISearchController = {
    let searchedResultVC = SearchedResultViewController.instanceFromNib()
    
    let searchController = UISearchController(searchResultsController: searchedResultVC)
    
    searchController.searchResultsUpdater = self
    searchController.obscuresBackgroundDuringPresentation = true
    searchController.searchBar.placeholder = "search_todos".localized
    searchController.searchBar.delegate = self

    return searchController
}()

override func viewDidLoad() {
    super.viewDidLoad()

    ...
    
    if navigationItem.searchController == nil {
        navigationItem.searchController = searchController
    }
}

该搜索栏会根据CollectionView的状态呈现不同表现:

空CollectionView - 搜索栏始终可见

空CollectionView时搜索栏可见

内容较多的CollectionView - 滚动后搜索栏可见

内容较多时滚动后搜索栏可见

但当CollectionView内容过少、无法滚动时,搜索栏会始终隐藏:

内容较少的CollectionView - 搜索栏始终隐藏

内容较少时搜索栏隐藏

请问这是正常行为吗?如何让搜索栏在需要搜索时保持可见?


回答

这是正常行为吗?

这是UIKit的默认行为:当导航栏关联的滚动视图(此处为CollectionView)内容不足以触发滚动时,系统会自动隐藏搜索栏,属于系统默认的布局适配逻辑。

如何让搜索栏始终可见?

有两种常用解决方案:

  1. 强制搜索栏始终显示
    直接设置navigationItem的hidesSearchBarWhenScrolling属性为false,无论CollectionView是否能滚动,搜索栏都会保持可见:
override func viewDidLoad() {
    super.viewDidLoad()

    ...
    
    if navigationItem.searchController == nil {
        navigationItem.searchController = searchController
        // 添加该行代码
        navigationItem.hidesSearchBarWhenScrolling = false
    }
}
  1. 动态控制显示状态
    如果需要根据内容灵活调整(比如内容较多时允许滚动隐藏,内容较少时强制显示),可以监听CollectionView的contentSize变化,动态设置hidesSearchBarWhenScrolling:
override func viewDidLoad() {
    super.viewDidLoad()
    
    ...
    
    // 监听contentSize变化
    collectionView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    guard keyPath == "contentSize", let collectionView = object as? UICollectionView else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        return
    }
    
    // 判断内容是否足够触发滚动
    let canScroll = collectionView.contentSize.height > collectionView.bounds.height
    navigationItem.hidesSearchBarWhenScrolling = canScroll
}

deinit {
    collectionView.removeObserver(self, forKeyPath: "contentSize")
}

内容的提问来源于stack exchange,提问作者Cheok Yan Cheng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:22:29