tvOS SearchController,避免折叠键盘

tvOS SearchController, avoid collapsing keyboard

我在 tvOS 中创建了一个 SearchController,它在带有水平滚动的 CollectionView 中显示结果。

最终结果看起来很糟糕,因为当焦点从键盘移到结果时,键盘会自动消失。

因为collection view的高度在没有键盘的情况下比较大,上面的元素会在collection view中自动重新对齐。这让用户体验非常混乱。

您可以在下面的 GIF 中看到问题。将焦点从键盘向下移动到结果,最终甚至会聚焦一个非预期的元素。 ("Seven" 而不是 "Five")

有什么办法可以避免键盘塌陷吗?。我注意到当结果视图包含不可滚动的视图时,键盘不会折叠,但我需要使我的结果可滚动。

在这里您可以找到重现该问题的代码。

import UIKit

private var items = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve"]

final class MySearchViewController: UIViewController, UICollectionViewDataSource {

    override func viewDidLoad() {
        super.viewDidLoad()
        setUpView()
    }

    // MARK: - Private

    private lazy var searchContainerViewController: UISearchContainerViewController = {
        return UISearchContainerViewController(searchController: searchController)
    }()

    private lazy var searchController: UISearchController = {
        let searchController = UISearchController(searchResultsController: searchResultsController)
        return searchController
    }()

    private lazy var searchResultsController: UIViewController = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal

        let searchResultsController = UICollectionViewController(collectionViewLayout: layout)
        searchResultsController.collectionView.dataSource = self
        MyCell.register(in: searchResultsController.collectionView)
        return searchResultsController
    }()

    private func setUpView() {
        embed(viewController: searchContainerViewController, inContainerView: view)
    }

    // MARK: - UICollectionViewDataSource

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCell.reuseIdentifier, for: indexPath) as! MyCell
        cell.titleLabel.text = items[indexPath.row]
        return cell
    }
}

class MyCell: UICollectionViewCell {

    static var reuseIdentifier: String { return String(describing: self) + "ReuseIdentifier" }

    var titleLabel: UILabel!

    public static func register(in collectionView: UICollectionView) {
        collectionView.register(MyCell.self, forCellWithReuseIdentifier: MyCell.reuseIdentifier)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        titleLabel = UILabel(frame: bounds)
        backgroundColor = .blue
        contentView.addSubview(titleLabel)
    }

    override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
        backgroundColor = isFocused ? .red : .blue
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

避免聚焦错误元素的解决方法是为 CollectionView 分配固定高度。但是这样做,仍然隐藏了键盘,在屏幕上留下了很多多余的空白space。

因为在这种情况下隐藏键盘是没有用的。我想让它始终可见。

这是集合视图使用固定高度的结果。

直到苹果发布新的 tvOS 14 属性 searchControllerObservedScrollViewhttps://developer.apple.com/documentation/uikit/uisearchcontroller/3584820-searchcontrollerobservedscrollvi

,这才真正成为可能

通过在此 属性 上设置您的 collectionView,SearchController 将自动使搜索栏 + 键盘位置适应您的 CollectionView 偏移量。

您可以这样调整您的代码:

    private lazy var searchController: UISearchController = {
        let searchController = UISearchController(searchResultsController: searchResultsController)
        if #available(tvOS 14.0, *) {
            searchController.searchControllerObservedScrollView = (searchResultsController as? UICollectionViewController)?.collectionView
        }
        return searchController
    }()

要摆脱可空转换,只需将 searchResultsController return 类型更改为 UICollectionViewController。它应该不会影响您的实施。