Swift 中的 TableView 搜索

TableView search in Swift

我有两个数组:FirstTableArray(包括品牌名称)和 SecondTableArray(包括型号)。

我想添加搜索功能,可以通过部分名称找到phone的型号。

import UIKit
import MessageUI

class FirstTableViewController: UITableViewController {

    var FirstTableArray = [String]()
    var SecondTableArray = [SecondTable]()

override func viewDidLoad() {

    super.viewDidLoad()

    self.navigationController?.navigationBar.isTranslucent = false
    self.navigationController?.navigationBar.barStyle = .black
    self.navigationController?.navigationBar.tintColor = UIColor.white

// First Table Array

    FirstTableArray = ["Apple", "Samsung"]

// Second Table Array

    SecondTableArray = [
    SecondTable(SecondTitle: ["iPhone 5s", "iPhone 6", "iPhone 6s"]),
    SecondTable(SecondTitle: ["Galaxy S4", "Galaxy S5", "Galaxy S6"]), 
    ]   
    }

 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
    return FirstTableArray.count
    }

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let Cell = self.tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
    Cell.textLabel?.text = FirstTableArray[(indexPath as NSIndexPath).row]
    return Cell
    }

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let indexPath : IndexPath = self.tableView.indexPathForSelectedRow!
    let DestViewController = segue.destination as! SecondTableViewController
    let SecondTableArrayTwo = SecondTableArray[(indexPath as NSIndexPath).row]
    DestViewController.SecondTableArray = SecondTableArrayTwo.SecondTitle
    } 
}

你能帮我解决这个问题吗?

我建议实现 UISearchBar 并将您的 class 作为委托添加到 UISearchBar,然后在委托方法中您可以获取搜索栏文本并在数据源上执行搜索,然后重新加载表视图数据因此

编辑:您可以使用本教程了解如何在 UITableView 上实现 UISearchBar https://www.raywenderlich.com/472-uisearchcontroller-tutorial-getting-started

我今天也在做同样的事情,发现这个教程很容易理解:https://github.com/codepath/ios_guides/wiki/Search-Bar-Guide

它将带您完成在 Interface Builder 中添加搜索栏、设置委托以及包含筛选结果的方法的步骤。


为用户提供一种搜索项目集合的方法是 iOS 项目中相当常见的任务。实现搜索行为的标准界面是搜索栏。

有几种使用搜索栏的常用方法:

  • 直接使用 UISearchBar。这是最简单的使用方法 UISearchBars。如果您想设计,这可以非常灵活 并编写您自己的搜索界面,但不提供 许多 built-in 功能与其他方法一样。

  • 使用 UISearchDisplayController 帮助管理搜索界面。 UISearchDisplayController 允许您呈现标准搜索 与 built-in 动画的界面。此方法强制您显示 在 table 视图中搜索结果。 - 已弃用

  • 使用 UISearchController 帮助管理搜索界面。
    UISearchController 是一个较新的控制器(仅在 iOS 8+ 中可用)
    帮助您使用任何类型的视图呈现搜索界面
    显示搜索结果。

本指南涵盖了使用这些 类 的基础知识。 None 其中 类 实际上实现了 "searching" 查找与给定查询字符串匹配的项目的行为,因为确定哪些对象匹配将随域特定用例而变化(例如,当搜索 "people" 你可能只想匹配他们的名字,而你可能想在搜索 e-mails 时进行 full-text pre-indexed 搜索。您必须自己实施任何 search/filtering 行为。

直接使用 UISearchBars

搜索栏的核心不过是一个美化的文本字段,其中包含一个范围控件、一些动画和几个按钮。每个搜索栏都有一个委托,让您有机会响应用户操作。最重要的委托方法是:

  • textDidChange - 大多数时候您会通过以下方式响应此事件 在用户输入时更新显示的搜索结果集 查询
  • searchBarSearchButtonClicked - 在某些情况下如果搜索操作 速度很慢(例如,需要进行缓慢的 API 调用)您需要等待 直到用户在更新搜索之前点击搜索按钮 结果。

搜索 table

的示例

我们从一个带有基本 UITableView 的单视图应用程序开始。您可以像添加任何其他控件一样添加 UISearchBar,方法是将一个控件拖到界面生成器中的视图控制器或以编程方式添加它。

搜索栏的委托 属性 必须设置为实现 UISearchBarDelegate 的对象。通常,您让视图控制器实现 UISearchBarDelegate 并在 viewDidLoad 方法中设置 searchBar.delegate = self。

实现搜索行为的代码如下。我们维护一个额外的数组 filteredData 来表示与我们的搜索文本匹配的数据行。当搜索文本更改时,我们更新 filteredData 并重新加载我们的 table.

class ViewController: UIViewController, UITableViewDataSource, UISearchBarDelegate {
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var searchBar: UISearchBar!

let data = ["New York, NY", "Los Angeles, CA", "Chicago, IL", "Houston, TX",
    "Philadelphia, PA", "Phoenix, AZ", "San Diego, CA", "San Antonio, TX",
    "Dallas, TX", "Detroit, MI", "San Jose, CA", "Indianapolis, IN",
    "Jacksonville, FL", "San Francisco, CA", "Columbus, OH", "Austin, TX",
    "Memphis, TN", "Baltimore, MD", "Charlotte, ND", "Fort Worth, TX"]

var filteredData: [String]!

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.dataSource = self
    searchBar.delegate = self
    filteredData = data
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath) as UITableViewCell
    cell.textLabel?.text = filteredData[indexPath.row]
    return cell
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return filteredData.count
}

// This method updates filteredData based on the text in the Search Box
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    // When there is no text, filteredData is the same as the original data
    // When user has entered text into the search box
    // Use the filter method to iterate over all items in the data array
    // For each item, return true if the item should be included and false if the
    // item should NOT be included
    filteredData = searchText.isEmpty ? data : data.filter({(dataString: String) -> Bool in
        // If dataItem matches the searchText, return true to include it
        return dataString.range(of: searchText, options: .caseInsensitive) != nil
    })

    tableView.reloadData()
}
}

这是 运行 时的样子。注意搜索结果显示在同一个table,并没有单独的搜索界面的呈现

搜索集合视图的示例

由于 UISearchBar 非常简单,它可以与任何任意视图组合以构建您自己的搜索界面。这是它与集合视图配对时的样子。

此代码与 table 视图的情况基本相同。

正在取消搜索并隐藏键盘

一旦用户点击搜索栏,键盘就会出现,你会注意到当你点击 X 时它不会消失。你可以在用户点击搜索栏时显示取消按钮,当用户点击在取消上,隐藏键盘。

UISearchBarDelegate 有一个漂亮的 searchBarTextDidBeginEditing 方法,当用户开始编辑搜索文本时会调用该方法。您可以在该方法中显示取消按钮:

func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
        self.searchBar.showsCancelButton = true
}

当用户点击取消按钮时,代理的 searchBarCancelButtonClicked 方法被调用。此时,您可以隐藏取消按钮,清除搜索栏中的现有文本并隐藏键盘,如下所示:

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        searchBar.showsCancelButton = false
        searchBar.text = ""
        searchBar.resignFirstResponder()
}

使用 UISearchControllers (iOS 8+)

一种管理搜索界面显示的新方法(仅在 iOS 8 及更高版本中可用)是通过 UISearchController。这个控制器处理一些逻辑和动画n 为您呈现单独的搜索界面,同时仍允许您指定搜索结果的显示方式。

搜索 table

的示例

UISearchController 的界面生成器对象库中目前没有 built-in 对象。创建一个最简单的方法是以编程方式进行。这也会创建一个 UISearchBar 并将搜索控制器的 searchBar 属性 设置为它。您可以通过编程方式将此搜索栏添加到您的视图层次结构中。

为了更新您的搜索结果,您必须实施 UISearchResultsUpdating 协议并设置搜索控制器的 searchResultsUpdater 属性。

您不需要实现 UISearchControllerDelegate,除非您需要挂钩围绕搜索界面显示的事件。

将所有代码放在一起看起来像这样。请注意,我们必须从 updateSearchResultsForSearchController 中的搜索栏中读取搜索文本。另一件需要注意的事情是我们将这个视图控制器的 definesPresentationContext 属性 设置为 true。这意味着搜索控制器在呈现搜索界面时应使用此视图控制器的框架(与根视图控制器相反)。在这种情况下,这意味着搜索界面将扩展到载体栏上方。

class ViewController: UIViewController, UITableViewDataSource, UISearchResultsUpdating {
    @IBOutlet weak var tableView: UITableView!

let data = ["New York, NY", "Los Angeles, CA", "Chicago, IL", "Houston, TX",
    "Philadelphia, PA", "Phoenix, AZ", "San Diego, CA", "San Antonio, TX",
    "Dallas, TX", "Detroit, MI", "San Jose, CA", "Indianapolis, IN",
    "Jacksonville, FL", "San Francisco, CA", "Columbus, OH", "Austin, TX",
    "Memphis, TN", "Baltimore, MD", "Charlotte, ND", "Fort Worth, TX"]

var filteredData: [String]!

var searchController: UISearchController!

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.dataSource = self
    filteredData = data

    // Initializing with searchResultsController set to nil means that
    // searchController will use this view controller to display the search results
    searchController = UISearchController(searchResultsController: nil)
    searchController.searchResultsUpdater = self

    // If we are using this same view controller to present the results
    // dimming it out wouldn't make sense. Should probably only set
    // this to yes if using another controller to display the search results.
    searchController.dimsBackgroundDuringPresentation = false

    searchController.searchBar.sizeToFit()
    tableView.tableHeaderView = searchController.searchBar

    // Sets this view controller as presenting view controller for the search interface
    definesPresentationContext = true
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("TableCell") as UITableViewCell
    cell.textLabel?.text = filteredData[indexPath.row]
    return cell
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return filteredData.count
}

func updateSearchResultsForSearchController(searchController: UISearchController) {
    if let searchText = searchController.searchBar.text {
        filteredData = searchText.isEmpty ? data : data.filter({(dataString: String) -> Bool in
            return dataString.rangeOfString(searchText, options: .CaseInsensitiveSearch) != nil
        })

        tableView.reloadData()
    }
}
}

这是 运行 时的样子。请注意,与搜索显示控制器示例不同,我们使用相同的 table 视图来显示搜索结果,而不是覆盖单独的 table 视图。然而,与仅使用搜索栏不同,我们在转换到搜索界面时仍然有内置动画。

此外,当您使用此功能时,当用户免费点击取消按钮时,您将获得显示取消按钮和隐藏键盘的逻辑。

搜索集合视图的示例

我们可以轻松地使用搜索控制器就地搜索集合视图。我们仍然有一个搜索界面的演示文稿,但与使用搜索显示控制器时不同,我们不限于使用 table 视图来显示搜索结果。

此代码与搜索上面的 table 视图时几乎相同。唯一没有table的区别是我们必须在界面构建器中为搜索栏引入占位符视图,因为将搜索控制器的搜索栏放置在集合视图的补充视图中仍然存在一些怪癖。

class ViewController: UIViewController, UICollectionViewDataSource, UISearchResultsUpdating {
    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet weak var searchBarPlaceholder: UIView!
    ...
    override func viewDidLoad() {
        ...
        searchController.searchBar.sizeToFit()
        searchBarPlaceholder.addSubview(searchController.searchBar)
        automaticallyAdjustsScrollViewInsets = false
        definesPresentationContext = true
    }

    ...
}

导航视图中的搜索栏

一个常见的要求是将搜索栏放在导航栏内。

这可以在您的视图控制器的 viewDidLoad 中以编程方式配置,如下所示。

直接使用搜索栏时:

// create the search bar programatically since you won't be
// able to drag one onto the navigation bar
searchBar = UISearchBar()
searchBar.sizeToFit()

// the UIViewController comes with a navigationItem property
// this will automatically be initialized for you if when the
// view controller is added to a navigation controller's stack
// you just need to set the titleView to be the search bar
navigationItem.titleView = searchBar

使用搜索显示控制器:

searchDisplayController?.displaysSearchBarInNavigationBar = true

使用搜索控制器:

searchController.searchBar.sizeToFit()
navigationItem.titleView = searchController.searchBar

// By default the navigation bar hides when presenting the
// search interface.  Obviously we don't want this to happen if
// our search bar is inside the navigation bar.
searchController.hidesNavigationBarDuringPresentation = false