如何判断自定义 UISearchBar 中的 UITableView 是不是被触摸?

Posted

技术标签:

【中文标题】如何判断自定义 UISearchBar 中的 UITableView 是不是被触摸?【英文标题】:How to tell if UITableView in custom UISearchBar is touched?如何判断自定义 UISearchBar 中的 UITableView 是否被触摸? 【发布时间】:2021-05-31 23:24:57 【问题描述】:

我正在尝试创建一个自定义 UISearchBar,它被放置为 titleViewtitleView。使用以下代码,建议的suggestionTableView 完美出现;但是,它不识别任何水龙头。事实上,就像suggestionTableView 甚至不存在一样,因为我的点击正在根据suggestionTableView 的建议发送到另一个视图。有人告诉我我可以使用hitTest(...) 来捕捉这些触摸,但我不知道如何在我的SuggestionSearchBarViewController 中实现这一点。如何将这些触摸发送到suggestionTableView

建议搜索栏

class SuggestionSearchBar: UISearchBar, UISearchBarDelegate 
    
    var suggestionTableView = UITableView(frame: .zero)
    let allPossibilities: [String]!
    var possibilities = [String]()
    //let del: UISearchBarDelegate!
    
    init(del: UISearchBarDelegate, dropDownPossibilities: [String]) 
        self.allPossibilities = dropDownPossibilities
        super.init(frame: .zero)
        isUserInteractionEnabled = true
        delegate = del
        searchTextField.addTarget(self, action: #selector(searchBar(_:)), for: .editingChanged)
        searchTextField.addTarget(self, action: #selector(searchBarCancelButtonClicked(_:)), for: .editingDidEnd)
        sizeToFit()
        addTableView()
    
    
    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    
    
    private func addTableView() 
        let cellHeight = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "").frame.height
        suggestionTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        suggestionTableView.backgroundColor = UIColor.clear
        //suggestionTableView.separatorStyle = .none
        suggestionTableView.tableFooterView = UIView()
        addSubview(suggestionTableView)
        
        suggestionTableView.delegate = self
        suggestionTableView.dataSource = self
        suggestionTableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            suggestionTableView.topAnchor.constraint(equalTo: bottomAnchor),
            suggestionTableView.rightAnchor.constraint(equalTo: rightAnchor),
            suggestionTableView.leftAnchor.constraint(equalTo: leftAnchor),
            suggestionTableView.heightAnchor.constraint(equalToConstant: cellHeight*6),
        ])
        hideSuggestions()
    
    
    func showSuggestions() 
        let sv = suggestionTableView.superview
        sv?.clipsToBounds = false
        suggestionTableView.isHidden = false
    
    
    func hideSuggestions() 
        suggestionTableView.isHidden = true
    
    
    @objc func searchBar(_ searchBar: UISearchBar) 
        print(searchBar.text?.uppercased() ?? "")
        showSuggestions()
        possibilities = allPossibilities.filter $0.contains(searchBar.text?.uppercased() ?? "")
        print(possibilities.count)
        suggestionTableView.reloadData()
        if searchBar.text == "" || possibilities.count == 0 
            hideSuggestions()
        
    
    
    @objc func searchBarCancelButtonClicked(_ searchBar: UISearchBar) 
        hideSuggestions()
    


extension SuggestionSearchBar: UITableViewDataSource, UITableViewDelegate 
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return possibilities.count
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = suggestionTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.backgroundColor = UIColor(red: 0.25, green: 0.25, blue: 0.25, alpha: 0.75)
        if traitCollection.userInterfaceStyle == .light 
            cell.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.75)
        
        cell.textLabel?.text = possibilities[indexPath.row]
        return cell
    
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        //add method that fills in and searches based on the text in that indexpath.row
        print("selected")
    
    

视图控制器

import UIKit

class ViewController: UIViewController 

    lazy var searchBar = SuggestionSearchBar(del: self, dropDownPossibilities: ["red","green","blue","yellow"])

    override func viewDidLoad() 
        super.viewDidLoad()
        setUpUI()
    

    func setUpUI() 
        setUpSearchBar()
    


extension ViewController: UISearchBarDelegate 
    
    func setUpSearchBar() 
        searchBar.searchBarStyle = UISearchBar.Style.prominent
        searchBar.placeholder = "Search"
        searchBar.sizeToFit()
        searchBar.isTranslucent = false
        searchBar.backgroundImage = UIImage()
        searchBar.delegate = self
        navigationItem.titleView = searchBar
    
    
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) 
        print(searchBar.text!)
    
    
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) 
        searchBar.endEditing(true)
    
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) 
        
    

【问题讨论】:

我认为这不是你真正需要的,但如果你想了解如何使用 hitTest,请搜索 UIView Swift hitTest。 您是否查看了我对您上一个问题的答案所做的编辑? ***.com/questions/67731865/… @DonMag 对不起,我想我错过了。我刚刚尝试过,但它仍然不允许我单击建议表视图单元格。您还有其他可行的建议吗? @ElTomato 你觉得我需要什么? @helloworld12345 请检查我的答案! 【参考方案1】:

查看您提供的代码,我可以让 UI 正常工作,甚至可以在 SuggestionSearchBar 中获取 UITableViewDelegate 回调。 以下是变化

建议搜索栏

class SuggestionSearchBar: UISearchBar, UISearchBarDelegate 
    
    var suggestionTableView = UITableView(frame: .zero)
    let allPossibilities: [String]!
    var possibilities = [String]()
    var fromController: UIViewController?
    //let del: UISearchBarDelegate!
    
    init(del: UISearchBarDelegate, dropDownPossibilities: [String], fromController: UIViewController) 
        self.fromController = fromController
        self.allPossibilities = dropDownPossibilities
        super.init(frame: .zero)
        isUserInteractionEnabled = true
        delegate = del
        searchTextField.addTarget(self, action: #selector(searchBar(_:)), for: .editingChanged)
        searchTextField.addTarget(self, action: #selector(searchBarCancelButtonClicked(_:)), for: .editingDidEnd)
        sizeToFit()
        addTableView()
    
    
    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    
    
    private func addTableView() 
        guard let view = fromController?.view else return
        let cellHeight = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "").frame.height
        suggestionTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        suggestionTableView.backgroundColor = UIColor.clear
        //suggestionTableView.separatorStyle = .none
        suggestionTableView.tableFooterView = UIView()
        view.addSubview(suggestionTableView)
//        addSubview(suggestionTableViewse
        
        suggestionTableView.delegate = self
        suggestionTableView.dataSource = self
        suggestionTableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            suggestionTableView.topAnchor.constraint(equalTo: view.topAnchor),
            suggestionTableView.rightAnchor.constraint(equalTo: view.rightAnchor),
            suggestionTableView.leftAnchor.constraint(equalTo: view.leftAnchor),
            suggestionTableView.heightAnchor.constraint(equalToConstant: cellHeight*6),
        ])

        hideSuggestions()
    
    
    func showSuggestions() 
        let sv = suggestionTableView.superview
        sv?.clipsToBounds = false
        suggestionTableView.isHidden = false
    
    
    func hideSuggestions() 
        suggestionTableView.isHidden = true
    
    
    @objc func searchBar(_ searchBar: UISearchBar) 
        print(searchBar.text?.uppercased() ?? "")
        showSuggestions()
        possibilities = allPossibilities.filter $0.contains(searchBar.text?.lowercased() ?? "")
        print(possibilities.count)
        suggestionTableView.reloadData()
        if searchBar.text == "" || possibilities.count == 0 
            hideSuggestions()
        
    
    
    @objc func searchBarCancelButtonClicked(_ searchBar: UISearchBar) 
        hideSuggestions()
    

视图控制器

class ViewController: UIViewController 

   lazy var searchBar = SuggestionSearchBar(del: self, dropDownPossibilities: ["red","green","blue","yellow"], fromController: self)

    override func viewDidLoad() 
        super.viewDidLoad()
        setUpUI()
    

    func setUpUI() 
        setUpSearchBar()
    

总结一下变化,上面的代码尝试添加suggestionTableView 到 SearchBarView 这是不可能的,所以我使用对存储为的父 ViewController 的引用初始化 SearchBarView

var fromController: UIViewController?

这个属性后来用在addTableView()

private func addTableView() 
        guard let view = fromController?.view else return
        let cellHeight = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "").frame.height
        suggestionTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        suggestionTableView.backgroundColor = UIColor.clear
        //suggestionTableView.separatorStyle = .none
        suggestionTableView.tableFooterView = UIView()
        view.addSubview(suggestionTableView)
//        addSubview(suggestionTableViewse

        suggestionTableView.delegate = self
        suggestionTableView.dataSource = self
        suggestionTableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            suggestionTableView.topAnchor.constraint(equalTo: view.topAnchor),
            suggestionTableView.rightAnchor.constraint(equalTo: view.rightAnchor),
            suggestionTableView.leftAnchor.constraint(equalTo: view.leftAnchor),
            suggestionTableView.heightAnchor.constraint(equalToConstant: cellHeight*6),
        ])

        hideSuggestions()
    

还有一个小改动

possibilities = allPossibilities.filter $0.contains(searchBar.text?.lowercased() ?? "")

@objc func searchBar(_ searchBar: UISearchBar)

结果

【讨论】:

【参考方案2】:

只要您将UITableView 作为子视图添加到SearchBarUINavigationBar,您就会不断发现这些触摸问题。

解决此问题的一种可能方法是在调用站点有一个空容器 UIView 实例(在您的情况下为 ViewController)并要求 SuggestionsSearchBar 在该容器内添加它的 tableView

SuggestionSearchBar(
    del: self, 
    suggestionsListContainer: <UIStackView_Inside_ViewController>, 
    dropDownPossibilities: ["red","green","blue","yellow"]
)

SuggestionsSearchBar 仍将管理有关 tableView 的数据源、委托、可见性等的所有内容。它只需要一个可以从调用站点保存它的 tableView 的视图。

更新

我只强调需要更改的相关部分 - 其他一切都保持不变。

class SuggestionSearchBar: UISearchBar, UISearchBarDelegate 
    
    init(del: UISearchBarDelegate, suggestionsListContainer: UIStackView, dropDownPossibilities: [String]) 
        //// All the current setUp
        addTableView(in: suggestionsListContainer)
    
    
    private func addTableView(in container: UIStackView) 
        //// All the current setUp
        container.addArrangedSubview(suggestionTableView)
        
        NSLayoutConstraint.activate([
            suggestionTableView.heightAnchor.constraint(equalToConstant: cellHeight*6),
            /// We need to assign only height here
            /// top, leading, trailing will be driven by container at call site
        ])
    


class ViewController: UIViewController 

    lazy var suggestionsListContainer: UIStackView = 
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.distribution = .fill
        stackView.translatesAutoresizingMaskIntoConstraints = false
        return stackView
    ()
    
    lazy var searchBar = SuggestionSearchBar(
        del: self,
        suggestionsListContainer: suggestionsListContainer,
        dropDownPossibilities: ["red","green","blue","yellow"]
    )

    func setUpUI() 
        setUpSearchBar()
        setUpSuggestionsListContainer()
    
    
    func setUpSuggestionsListContainer() 
        self.view.addSubview(suggestionsListContainer)
        
        NSLayoutConstraint.activate([
            suggestionsListContainer.topAnchor.constraint(equalTo: self.view.topAnchor),
            suggestionsListContainer.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            suggestionsListContainer.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
            /// Height is not needed as it will be driven by tableView's height
        ])
    

【讨论】:

我需要在 SuggestionSearchBar 类中添加什么代码? 不是将tableView添加到self addSubview(suggestionTableView),而是将其添加到传入的suggestionsListContainer,如suggestionsListContainer.addArrangedSubview(suggestionTableView) 你能在你的答案中写出代码来展示如何在 ViewController 和 SuggestionSearchBar 中实现 请参阅更新我的回答。 我试过用这个,但是之前出现的suggestionTableView现在已经不出现了,请问有这个原因吗?

以上是关于如何判断自定义 UISearchBar 中的 UITableView 是不是被触摸?的主要内容,如果未能解决你的问题,请参考以下文章

自定义 NavigationBar 中的 UISearchBar

自定义键盘文本完全替换 UISearchBar 中的文本,而不是添加到其中 [iOS]

UISearchBar 自定义

如何在带有标题视图和 UITableview 的自定义视图中正确设置 UISearchbar 的动画?

在 iOS 7 中自定义 UISearchBar

如何使 UISearchBar 的书签图标可访问?