如何在Swift中实现UITableView中的UISearchController

48

我是Swift的新手,尝试在一个UIViewController类中的UITableView中添加搜索功能。我进行了大量谷歌搜索,发现UISearchDisplayController已被弃用并被UISearchController替代。当我尝试寻找教程时,没有找到特别针对UITableView的内容,其中一些仅适用于在UITableViewController中实现。所以我的问题如下:

  1. 我们可以在UIViewController类中的UITableView中实现UISearchController吗?(我猜我们可以)

  2. 如果可以,请将这些使用Objective-C编写的代码转换为Swift代码。如果有一些非常好的教程,请让我知道。

@property (strong, nonatomic) UISearchController *searchController;

UITableViewController *searchResultsController = [[UITableViewController alloc] init];

// Init UISearchController with the search results controller
 self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];

// Link the search controller
self.searchController.searchResultsUpdater = self;

来源

编辑: 我试图将搜索结果更新器分配为

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchResultsUpdating {

    override func viewDidLoad() {

       super.viewDidLoad()
       self.view.backgroundColor = UIColor.blackColor() 
       self.addTableViewWithSection() 
       self.searchResultsController = UITableViewController()           
       var controller = UISearchController(searchResultsController: nil)            
       controller.searchResultsUpdater = self           
       controller.dimsBackgroundDuringPresentation = false   
    }
}

然而,在控制器这一行中,controller.searchResultsUpdater = self,我得到了一个错误,提示无法将 "ViewController" 类型的值分配给 "UISearchResultsUpdating?" 类型的值。 所以我真的怀疑我是否可以在 UIViewController 类型的类中使用 UISearchController

3个回答

74

是的,搜索功能的工作方式已经被彻底改变,我认为新系统更好。对于大多数简单的实现,新系统更加高效和直观。使用它非常简单。

首先,确保您的类遵循UISearchResultsUpdating协议:

class MyTableViewController: UITableViewController, UISearchResultsUpdating {}

然后添加搜索控制器属性:

class MyTableViewController: UTableViewController, UISearchResultsUpdating {
    let searchController = UISearchController(searchResultsController: nil)
}
在viewDidLoad方法中添加搜索栏。
override func viewDidLoad() {
    super.viewDidLoad()

    searchController.searchResultsUpdater = self
    searchController.hidesNavigationBarDuringPresentation = false
    searchController.dimsBackgroundDuringPresentation = false
    searchController.searchBar.sizeToFit()
    self.tableView.tableHeaderView = searchController.searchBar
}

最后,实现来自UISearchResultsUpdating协议的updateSearchResults:for方法:

func updateSearchResults(for searchController: UISearchController) {

}

当然,这个方法的实现取决于你从哪里搜索数据。它会在你输入内容时更新当前的表视图以显示搜索的内容。确保在updateSearchResultsForSearchController方法中更新你的数据源并重新加载表视图。同样地,它是在你输入的同时进行更新的,因此请确保如果你要搜索的数据很大或者你从互联网进行搜索,则在此方法中添加一些并发。

如果你想用一个不同的控制器来填充你的搜索结果,那么在初始化searchController属性时可以传递该VC。

编辑:我重新阅读了你的问题,发现我忘记添加一些重要的内容。

UITableViewController有一个成员叫做tableView。你可以获取控制器的表视图,但是为了填充你的UITableView,你不需要直接操作它。你不能直接使用SearchController的逻辑与UITableView配合使用。你需要通过控制器来达到目的。使用UITableViewController委托和数据源方法来更新你的表UI并显示你的搜索结果。

请阅读有关UITableViewController、UITableViewDelegate和UITableViewDataSource的内容,以便了解如何将你的搜索结果放到那里。


如果这一行是 class MyTableViewController: UITableViewController, UISearchResultsUpdating {} ,假设将其作为 class MYTableView: UIViewController,并在那里创建tableview或者有一个outlet,这样会有效吗? - user4790024
类名并不重要,但是去掉“Controller”这部分没有意义,因为你实际上定义的是控制器而不是视图。另外,你不需要手动创建UITableView,因为UITableViewController已经为你准备好了一个可以使用的表格视图。无论你是在IB中创建此控制器还是完全通过代码,你的控制器都可以通过self.tableView引用它。但同样,你不需要这样做来填充您的表格视图。 - Andy Ibanez
1
我已经有一个包含许多子视图和大型表格视图的ViewController,现在我需要为该表格视图实现搜索功能...所以,我正在寻找解决方法...无论如何,谢谢!我会尝试实现这个功能。 - user4790024
你能否看一下更新后的问题吗?我现在真的卡住了。 - user4790024
1
如果您想添加到任何UIView中,那么可以使用myView.addSubview(searchController.searchBar) - Ariq
显示剩余2条评论

27

对于那些像我一样搞疯了的人..这段代码可能会有所帮助

class ViewController: UIViewController , UITableViewDataSource, UITableViewDelegate,UISearchResultsUpdating {

    @IBOutlet weak var tblView: UITableView!

    var tabledata = ["lucques","chickendijon","godaddy","amazon","chris","ambata","bankofamerica","abelcine","AUTO + TRANSPORTATION","BILLS + UTILITIES","FOOD + DINING","HEALTH","AutoCare", "Auto Payment" , "Gas+Fuel","Electric Bill", "Internet/Television","Fast Foodd", "Gorceries" , "Restaurants","Gym Membership", "Health Insurance","auto","note-bullet","knife","heart"]

    var filteredTableData = [String]()
    var resultSearchController = UISearchController()

    override func viewDidLoad() {
        super.viewDidLoad()
        tblView.delegate = self
        tblView.dataSource = self
        self.resultSearchController = ({
            let controller = UISearchController(searchResultsController: nil)
            controller.searchResultsUpdater = self
            controller.dimsBackgroundDuringPresentation = false
            controller.searchBar.sizeToFit()
            controller.searchBar.barStyle = UIBarStyle.Black
            controller.searchBar.barTintColor = UIColor.whiteColor()
            controller.searchBar.backgroundColor = UIColor.clearColor()
            self.tblView.tableHeaderView = controller.searchBar
            return controller
        })()
        self.tblView.reloadData()
    }

     func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if self.resultSearchController.active {
           return self.filteredTableData.count
        }else{
            return self.tabledata.count
       }
    }
     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var section = indexPath.section
        var row = indexPath.row
        let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier:"addCategoryCell")
        cell.selectionStyle =  UITableViewCellSelectionStyle.None
        cell.backgroundColor = UIColor.clearColor()
        cell.contentView.backgroundColor = UIColor.clearColor()
        cell.textLabel?.textAlignment = NSTextAlignment.Left
        cell.textLabel?.textColor = UIColor.blackColor()
        cell.textLabel?.font = UIFont.systemFontOfSize(14.0)

        if self.resultSearchController.active {
              cell.textLabel?.text = filteredTableData[indexPath.row]
        } else {
                 cell.textLabel?.text = tabledata[indexPath.row]
        }
        return cell
    }

    func updateSearchResultsForSearchController(searchController: UISearchController) {
        filteredTableData.removeAll(keepCapacity: false)
        let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@", searchController.searchBar.text)
        let array = (tabledata as NSArray).filteredArrayUsingPredicate(searchPredicate)
        filteredTableData = array as! [String]
        self.tblView.reloadData()

    }
}

1
你的假设是可以在作用域中初始化变量,这是非常非常糟糕的假设。永远不要在方法体中使用self.resultSearchController进行操作。 - TheCodingArt
我应该创建那个懒惰变量并进行初始化吗? - user4790024
是的,如果您希望将所有初始化放在一个地方,那么非常适合。 - TheCodingArt
是的,那可能很好。这是我学习SearchController时使用的一个。 - user4790024
如果我想获取搜索结果的indexPath,并且有一个segue,如何读取搜索结果的indexPath?谢谢。 - Chathuranga Silva
1
在搜索后,您可以使用tableview的didselectrowatindexpath委托方法并从那里进行segue。 - user4790024

0

对于那些想要更多了解如何实现UISearchController的方方面面的人,这里有一个实现UISearchController的教程

除了Andy Ibanez提供的答案之外,您还需要在UITableViewDataSource方法中添加代码,以在表格视图中显示新过滤的结果。

此外,在updateSearchResults方法中不要忘记调用tableView.reloadData() - UISearchController不会自动告诉tableView重新加载其数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接