iOS UISearchController和UITableView

时间:2020-02-23 14:45:57  来源:igfitidea点击:

在本教程中,我们将开发一个应用程序,该应用程序使用UISearchController在TableView上实现搜索功能。
我们在此处的Android教程中做了类似的操作。

UISearchController

UISearchController包含协议" UISearchResultsUpdating",每当UISearchBar中的文本发生更改时,该协议就会通过下面提供的函数通知ViewController类。

func updateSearchResults(for searchController:UISearchController)

在以下应用程序中,我们将使用TableViewController作为默认的视图控制器类型,并以编程方式在其顶部添加一个UISearchController(UISearchController在Interface Builder中不可用)。
我们将使用Subtitle样式的TableViewCell,它在每行中包含一个标题和一个描述,并将使用Model类填充该描述。

iOS UISearchController示例项目结构

UISearchController示例代码

创建一个新文件" Model.swift",该文件存储每一行的数据。

import Foundation

struct Model {
  let movie : String
  let genre : String
}

下面给出了ViewController.swift源代码。

import UIKit

class ViewController: UITableViewController {

  var models = [Model]()
  var filteredModels = [Model]()
  let searchController = UISearchController(searchResultsController: nil)
  
  override func viewDidLoad() {
      super.viewDidLoad()
      //Do any additional setup after loading the view, typically from a nib.
      
      self.tableView.tableFooterView = UIView()
      
      setupSearchController()
      
      models = [
          Model(movie:"The Dark Night", genre:"Action"),
          Model(movie:"The Avengers", genre:"Action"),
          Model(movie:"Logan", genre:"Action"),
          Model(movie:"Shutter Island", genre:"Thriller"),
          Model(movie:"Inception", genre:"Thriller"),
          Model(movie:"Titanic", genre:"Romance"),
          Model(movie:"La la Land", genre:"Romance"),
          Model(movie:"Gone with the Wind", genre:"Romance"),
          Model(movie:"Godfather", genre:"Drama"),
          Model(movie:"Moonlight", genre:"Drama")
      ]
      
  }

  override func didReceiveMemoryWarning() {
      super.didReceiveMemoryWarning()
      //Dispose of any resources that can be recreated.
  }
  
  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
      
      let model: Model
      if searchController.isActive && searchController.searchBar.text != "" {
          model = filteredModels[indexPath.row]
      } else {
          model = models[indexPath.row]
      }
      cell.textLabel!.text = model.movie
      cell.detailTextLabel!.text = model.genre
      return cell
  }
  
  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      if searchController.isActive && searchController.searchBar.text != "" {
          return filteredModels.count
      }
      
      return models.count
  }
  
  override func numberOfSections(in tableView: UITableView) -> Int {
      return 1
  }

  func setupSearchController() {
      definesPresentationContext = true
      searchController.dimsBackgroundDuringPresentation = false
      searchController.searchResultsUpdater = self
      searchController.searchBar.barTintColor = UIColor(white: 0.9, alpha: 0.9)
      searchController.searchBar.placeholder = "Search by movie name or genre"
      searchController.hidesNavigationBarDuringPresentation = false
      
      tableView.tableHeaderView = searchController.searchBar
  }
  
  
  
  func filterRowsForSearchedText(_ searchText: String) {
      filteredModels = models.filter({( model : Model) -> Bool in
          return model.movie.lowercased().contains(searchText.lowercased())||model.genre.lowercased().contains(searchText.lowercased())
      })
      tableView.reloadData()
  }

  
  
}
extension ViewController: UISearchResultsUpdating {
  func updateSearchResults(for searchController: UISearchController) {
      if let term = searchController.searchBar.text {
          filterRowsForSearchedText(term)
      }
  }
}

ew!那是一个很大的代码。
让我们逐步了解这一点。

  • ViewController类实现UITableViewController。
    因此,无需分别实现Delegate和DataSource协议

  • models数组将包含所有行的数据。
    根据我们要设置的条件,filteredModels数组将包含与搜索到的字词匹配的行的数据

  • 初始化UISearchController的行是:
    通过将" searchResultsController"设置为nil,我们声明搜索结果将在当前TableViewController本身而不是其他View中更新。

  • 为了摆脱空行,我们称之为:

  • 让我们在SearchController上设置一些功能。

通过将definePresentationContext设置为true,我们确保将搜索控制器显示在原始表视图控制器的范围内。

  • " searchResultsUpdater"符合" UISearchResultsUpdating"协议。
    设置此选项可确保每次searchBar中的文本更改时,都会调用扩展中存在的updateSearchResults函数。

  • 如果searchBar是否包含某些文本,则TableView的cellForRowAt和numberOfRowsInSection会显示过滤的模型或者模型类中的相关数据。

  • 每次在方法updateSearchResults中更改文本时,都会调用filerRowsForSearchedText函数。

在上面的函数中,我们过滤了"模型"数组,仅将那些元素复制到"过滤的模型"中,该模型是"模型.movie"或者"模型.genre"类的子字符串。

  • 在上面的代码中,filter方法内部的部分具有不同的语法。
    称为"关闭"。

filter()采用类型为(model:Model)-> Bool的闭包,并遍历整个数组,仅返回与条件匹配的那些元素。

什么是封包?

闭包是一种没有关键字" func"的匿名函数。
" in"关键字用于将输入参数与返回部分分开。

闭包的示例是:

let searchController = UISearchController(searchResultsController: nil)

输入参数为Int,后跟->,返回类型再次为Int。

我们可以调用类似于函数调用的闭包。