带有范围过滤器的UISearchController

允许用户筛选您的列表可以改善用户的整体体验。 在这里,我们将学习如何使用现有的表格视图配置UISearchController并应用搜索栏。 因此,让我们直接进入。

入门项目

让我们从以下针对iOS 8及更高版本的入门项目开始。 我在以前的文章中没有使用过Storyboard,所以我决定在这里使用它。 如果您现在运行该应用程序,将会看到一个宠物小精灵的列表,其中包含它们的名称,元素和图像。 我们将要交互的主要文件如下

  • Pokemon.swift —包含宠物小精灵的名称,元素和图像的模型类
  • PokemonDataSource.swift —包含用于生成口袋妖怪列表的类方法
  • ViewController.swift —显示宠物小精灵的列表

配置SearchController

在ViewController.swift中,让我们添加到我们的searchController中。 注意,我们为参数传递了nil。

如果要在显示可搜索内容的同一视图控制器中显示搜索结果,请指定nil。

 私人让searchController = UISearchController(searchResultsController:nil) 

现在,我们有一个要管理的UISearchController实例,让我们继续进行配置。 在函数configureSearchController()中,添加以下内容

  searchController.dimsBackgroundDuringPresentation = false 
  definePresentationContext = true 
  tableView.tableHeaderView = searchController.searchBar 

通过将dimsBackgroundDuringPresentation设置为false,我们可以通知searchController在激活背景时不要使其背景变暗。 您应该将其设置为yes只是为了第一手看到它。 注意,我们将definePresentationContext设置为true。 这样可以确保,如果我们导航到另一个视图控制器,则搜索栏应仅保留在原始视图控制器中。 您应该看到以下内容; 但是,您会注意到搜索当前无效。 因此,让我们添加此功能!

文字过滤器

我们首先需要遵守UISearchResultsUpdating协议,以利用方法updateSearchResultsForSearchController(:)

每当搜索栏成为第一响应者或对搜索栏中的文本进行更改时,都会自动调用此方法。 在此方法内部执行所有必需的筛选和更新。

现在,我们将扩展ViewController使其符合UISearchResultsUpdating。 在这里,我们将实现此方法并将其调用filterSearchController(:)。 我们将在短期内重用filterSearchController。

  func updateSearchResultsForSearchController(searchController:UISearchController) 
{
  filterSearchController(searchController.searchBar) 
  } 

由于我们将显示已过滤的宠物小精灵的列表,因此我们不想破坏我们的pokemonList数组。 为了保留我们原来的pokemonList,我们将一个filteredPokemonList变量添加到我们的ViewController中。 注意它是可变的,因为它将经常更改。

 私人varfilteredPokemonList = [Pokemon]() 

在ViewController.swift中,继续并使用以下代码实现filterSearchController(searchBar:UISearchBar)。

 让searchText = searchBar.text ??  ” 
  filteredPokemonList = pokemonList.filter {pokemon in 
 让isMatchingSearchText = pokemon.name.lowercaseString.containsString(searchText.lowercaseString)||  searchText.lowercaseString.characters.count == 0 
 返回isMatchingSearchText 
  } 
  tableView.reloadData() 

我们首先获取searchText并使用Swift的高阶过滤器来过滤我们的pokemonList。 我们确保口袋妖怪的名称包含输入的字符串。 如果searchText为空,则应全部显示。 如果我们不添加第二个条件,那么当searchBar为空时,我们什么也看不到! 这将更新filterPokemonList并因此更新tableview。 但是,等等,我们的tableview如何知道何时使用filteredPokemonList和pokemonList? 只需通过更新cellForRowAtIndexPath(:)和numberOfRowsInSection(:)来说明searchController的活动状态即可。

在cellForRowAtIndexPath中,继续并使用以下一个衬里更新我们的pokemon变量。

 让pokemon = searchController.active吗?  filteredPokemonList [indexPath.row]:pokemonList [indexPath.row] 

? :语法称为三元运算符。 它说,如果searchController是活动的,则使用filteredPokemonList [indexPath.row],否则使用pokemonList [indexPath.row]。 否则,可以将其视为一个衬板。

现在,在numberOfRowsInSection中,我们要确保使用了正确的行数,因此让我们对其进行更新。

 返回searchController.active吗?  filteredPokemonList.count:pokemonList.count 

最后一件事,请确保将searchController的委托设置为self,以便它将在configureSearchController中侦听这些更改。

  searchController.searchResultsUpdater =自我 

多数民众赞成在基本的文本过滤!

范围过滤器

如果我们可以添加其他级别的过滤,那就太好了。 事实证明,我们可以做到,并且可以使用UISearchBar进行烘焙。 有了这些作用域,我们现在可以按元素进行筛选,例如火,水,草,甚至所有元素。

让我们更新configureSearchController(),以便获得此功能。 添加以下行。

  searchController.searchBar.scopeButtonTitles = [“所有”,“草”,“火”,“水”] 

您可以运行项目以查看创建的scopeButtonTitles。

再一次,我们将需要遵守协议,以便我们知道何时选择了过滤器范围并应用必要的过滤器。 让我们通过再次扩展ViewController来符合UISearchBarDelegate。 我们将在回调方法selectedScopeButtonIndexDidChange中重用我们的方法filterSearchController,因为我们实际上是在再次过滤。

  func searchBar(searchBar:UISearchBar,selectedScopeButtonIndexDidChange selectedScope:Int){ 
  filterSearchController(searchBar) 
  } 

确保在configureSearchController中设置searchBar的委托,以便通知ViewController。

  searchBar.delegate =自我 

现在,我们应该更新filterSearchController来考虑元素过滤器。

 守卫let scopeString = searchBar.scopeButtonTitles?[searchBar.selectedScopeButtonIndex] else {return} 
 让selectedElement = Pokemon.Element(rawValue:scopeString)??  。所有 
 让searchText = searchBar.text ??  ” 
  //通过元素和文本过滤pokemonList 
  filteredPokemonList = pokemonList.filter {pokemon in 
 让isElementMatching =(selectedElement == .All)||  (pokemon.element == selectedElement) 
 让isMatchingSearchText = pokemon.name.lowercaseString.containsString(searchText.lowercaseString)||  searchText.lowercaseString.characters.count == 0 
 返回isElementMatching && isMatchingSearchText 
  } 
  tableView.reloadData() 

请注意已进行的细微更改。 scopeString是通过selectedIndex处的searchBar的buttonTitles获得的。 然后我们创建一个枚举,因为它将是元素类型的四种可能性中的任何一种。 过滤器现在通过快速布尔检查考虑了elementMatching。 现在,如果口袋妖怪的元素与用户的选择匹配,并且searchText匹配,它将被添加到filterList中。

测试

继续进行下去。 现在,您有了具有过滤器和范围过滤器功能的表格视图! 完整的项目在这里。