如何在具有多个部分的TableView中使用searchBar?

时间:2019-09-02 11:36:22

标签: ios swift uitableview uisearchbar

这是我的情况:我在一个包含4个部分的导航器中有一个表格视图,每个部分都有一定数量的单元格。我想使用搜索栏查看表格视图的内容,但是我无法做到这一点,我所遵循的教程仅描述了1个表格视图,其中包含1个部分和一个“行数为n“,但是关于具有n个部分和每部分m行的表视图,则没有任何意义。我找到的人还没有答案。因此,我想请大家帮忙,以了解如何在我之前提到的条件下实现搜索栏。

如前所述,我有一个包含4个部分的表格视图,每个部分都有一些单元格,当我单击一个单元格时,它将带我到另一个视图控制器,该控制器具有一个textView,显示该部分和该行的数据。我想实现一个搜索栏,以便用户不必在整个表格视图中向下滚动即可找到所需的信息,但到目前为止,我还没有找到使用带有部分搜索栏的教程/示例,他们使用带有一个部分和许多单元的单个tableview。我已经尝试实现SearchBarDelegate(使用我发现的教程),但是它没有按预期工作。 因此,在这里我来找您,请您分享一些知识和智慧,以帮助我解决这个问题。

这是我的tableViewController的代码(/ * * /之间的代码是未实现searchBar的代码,因此它将仅显示具有其部分和单元格的表视图):

import UIKit

class TableViewController: UITableViewController {
// MARK: - Variables and Constants
var selectedIndex = Int()
var selectedSection = Int()
var textKind = [
    ["""
    SECTION 1, ROW 0 \n
    Esto debe venir de section 1 row 0, y para hacerlo realmente largo es necesario meter un montón de cosas irrelevantes para ver si respeta los espacios y los renglones del textView. Gracias de nada.
    """,
     """
    SECTION 1, ROW 1 \n
    Esto debe venir de section 1 row 1. Una vez más es necesario asegurarse de que los márgenes y formatos de texto son respetados. De otro modo habrá que corregirlos. \n
    Aquí hay un salto de línea. A ver qué tal sale.
    """,

    """
    SECTION 1, ROW 2 \n
    Esto debe venir de section 1 row 2. \n \n

    OTRO SUBTÍTULO DENTRO DE LA SECCIÓN. \n
    Se usarán 2 nuevas líneas cuando haya que añadir algún título o subtítulo dentro del textView. Por cuestiones de estética visual.
    """,

    """
    SECTION 1, ROW 3 \n
    Esto debe venir de section 1 row 3
    """],

    ["""
    SECTION 2 ROW 0 \n
    Esto debe venir de section 2 row 0. Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. \n \n \n \n \n \n

        Aquí sigue la onda pedorra.
    """,
     "Esto debe venir de section 2 row 1",
     "Esto debe venir de section 2 row 2",
     "Esto debe venir de section 2 row 3",
     "Esto debe venir de section 2 row 4",
     "Esto debe venir de section 2 row 5",
     "Esto debe venir de section 2 row 6"],

    ["Esto debe venir de section 3 row 0",
     "Esto debe venir de section 3 row 1",
     "Esto debe venir de section 3 row 2"],

    ["Esto debe venir de section 4 row 0",
     "Esto debe venir de section 4 row 1",
     "Esto debe venir de section 4 row 2",
     "Esto debe venir de section 4 row 3",
     "Esto debe venir de section 4 row 4",
     "Esto debe venir de section 4 row 5",
     "Esto debe venir de section 4 row 6",
     "Esto debe venir de section 4 row 7"]
]

var sectionsNames:[String] = ["section 1", "section 2", "section 3" , "section 4"]
var section1Content:[String] = ["uno", "dos", "tres", "cuatro"]
var section2Content:[String] = ["a", "be", "ce", "de", "e", "efe", "ge"]
var section3Content:[String] = ["alpha", "beta", "gamma"]
var section4Content:[String] = ["ichi", "ni", "san", "shi", "go", "roku", "nana", "hachi"]
@IBOutlet weak var searchBarVariable: UISearchBar!
var searching = false
var searchingData = [String]()

// MARK: - viewDidLoad()
override func viewDidLoad() {
    super.viewDidLoad()
    searchBarVariable.delegate = self
}

// MARK: - TableView configuration (sections, cellForRowAt, etc.).
// MARK: - Number of sections
override func numberOfSections(in tableView: UITableView) -> Int {
    return sectionsNames.count
}

// MARK: - Sections' titles
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return sectionsNames[section]
}

// MARK: - Number of rows per section
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    if searching {
        return searchingData.count
    } else {
        switch section {
        case 0:
            return section1Content.count

        case 1:
            return section2Content.count

        case 2:
            return section3Content.count

        case 3:
            return section4Content.count

        default:
            return 0
        }
    }

   /* switch section {
    case 0:
    return section1Content.count

    case 1:
        return section2Content.count

    case 2:
        return section3Content.count

    case 3:
        return section4Content.count

    default:
        return 0
    } */
}

// MARK: - Cells' content
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = self.tableView.dequeueReusableCell(withIdentifier: "sourceCell", for: indexPath)

    if searching {
        cell.textLabel?.text = searchingData[indexPath.row]
    } else {
        switch indexPath.section {
        case 0:
            cell.textLabel!.text = section1Content[indexPath.row]

        case 1:
            cell.textLabel!.text = section2Content[indexPath.row]

        case 2:
            cell.textLabel!.text = section3Content[indexPath.row]

        case 3:
            cell.textLabel!.text = section4Content[indexPath.row]
        default:
            break
        }
    }

    /*switch indexPath.section {
    case 0:
        cell.textLabel!.text = section1Content[indexPath.row]

    case 1:
        cell.textLabel!.text = section2Content[indexPath.row]

    case 2:
        cell.textLabel!.text = section3Content[indexPath.row]

    case 3:
        cell.textLabel!.text = section4Content[indexPath.row]
    default:
        break
    } */

    return cell
}

// MARK: - DidSelectRowAt
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    self.selectedSection = indexPath.section
    self.selectedIndex = indexPath.row
    performSegue(withIdentifier: "goToInfo", sender: self)
}

// MARK: - prepare(for segue:...)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "goToInfo" {
        let vc: ViewController = segue.destination as! ViewController
        vc.viewTextText = textKind[self.selectedSection][self.selectedIndex]
        print(vc.viewTextText)
    }
}
}

// MARK: - Searchbar in tableview
extension TableViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    searchingData = section1Content.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()}) + section2Content.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()}) + section3Content.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()}) + section4Content.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()})
    searching = true
    tableView.reloadData()
}

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    searching = false
    searchBar.text = ""
    tableView.reloadData()
}
}

这是链接到上一个tableViewController的viewController的代码:

import UIKit

class ViewController: UIViewController {

//MARK: - Variables and Constants
var viewTextText:String = ""

// MARK: - ViewController components
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var viewTextViewText: UITextView!
@IBOutlet weak var imageView: UIImageView!

// MARK: - viewDidLoad()
override func viewDidLoad() {
    super.viewDidLoad()
    arrangingTextView()
}

func arrangingTextView() {
    self.viewTextViewText.text = viewTextText
    self.viewTextViewText.font = UIFont(name: "helvetica", size: 24.0)
    self.viewTextViewText.textAlignment = .justified
}
}

期望值:在搜索栏中键入内容时,必须仅在搜索栏中显示具有匹配键入内容的部分和单元格。当我单击所需的信息时,它应该带我到包含该部分和单元格信息的viewController。

实际发生的情况:在搜索栏中键入内容时,它会在4个部分及其内容中显示相同的内容。当我单击该行时,它会将我带到与该单元格无关的虚假信息。

如果您复制我的代码,您将更好地理解我的意思。

1 个答案:

答案 0 :(得分:0)

此方法不合适。无需将标志变量用作searching并处理不同的情况,您所需要做的就是为整个过程仅定义一个数组。在您的情况下,您的数据源数组将如下所示:

[["uno", "dos", "tres", "cuatro"],["a", "be", "ce", "de", "e", "efe", "ge"],["alpha", "beta", "gamma"],["ichi", "ni", "san", "shi", "go", "roku", "nana", "hachi"]] 

现在,一切都变得更加易于处理和实施。例如,行数委托函数中的开关大小写将替换为:

return dataSource[section].count

您要做的是在点击搜索结果时将两个不同的数组相互映射。我建议您在具有与一件事情相关的多个属性时创建一个类:

struct Item {
var title : String // this is cell's title
var text : String // this is what will be shown on the next view controller when a cell is tapped.
}

您的数据源将如下所示:

var dataSource : [[Item]] = [[Item(title: "uno" , text: """
SECTION 1, ROW 0 \n
Esto debe venir de section 1 row 0, y para hacerlo realmente largo es necesario meter un montón de cosas irrelevantes para ver si respeta los espacios y los renglones del textView. Gracias de nada.
""") , Item(title: "dos" , text: """
SECTION 1, ROW 1 \n
Esto debe venir de section 1 row 1. Una vez más es necesario asegurarse de que los márgenes y formatos de texto son respetados. De otro modo habrá que corregirlos. \n
Aquí hay un salto de línea. A ver qué tal sale.
""" ) , Item(title: "tres" , text: """
SECTION 1, ROW 2 \n
Esto debe venir de section 1 row 2. \n \n

OTRO SUBTÍTULO DENTRO DE LA SECCIÓN. \n
Se usarán 2 nuevas líneas cuando haya que añadir algún título o subtítulo dentro del textView. Por cuestiones de estética visual.
""" ), Item(title: "cuatro" , text: """
SECTION 1, ROW 3 \n
Esto debe venir de section 1 row 3
""" )] , [Item(title: "a" , text: """
SECTION 2 ROW 0 \n
Esto debe venir de section 2 row 0. Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. \n \n \n \n \n \n

Aquí sigue la onda pedorra.
""" ) , Item(title: "be" , text: "Esto debe venir de section 2 row 1" ) , Item(title: "ce" , text: "Esto debe venir de section 2 row 2" ) , Item(title: "de" , text: "Esto debe venir de section 2 row 3" ) , Item(title: "e" , text: "Esto debe venir de section 2 row 4" ) , Item(title: "efe" , text: "Esto debe venir de section 2 row 1" ) , Item(title: "ge" , text: "Esto debe venir de section 2 row 5" )]]

现在,在您的搜索委托函数中,您需要根据文本从数据源数组中删除不需要的结果,或者在轻按“取消”按钮时将数组重置为默认值。完成此操作后,您只需重新加载表格视图即可:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    self.dataSource = values
    var filteredDataSource : [[Item]] = []
    for items in dataSource {
        let filteredItems = items.filter { (item) -> Bool in
            if item.title.lowercased().prefix(searchText.count) == searchText.lowercased() {
                return true
            }
            return false
        }
        filteredDataSource.append(filteredItems)
    }
    self.dataSource = filteredDataSource
    tableView.reloadData()

}

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    self.dataSource = values //reseting data source to defaults
    tableView.reloadData()
}

当您选择一行时,您在代码中错误地传递了节和行号。为了将相应的数据适当地传递给下一个视图控制器,您需要在准备segue功能中执行以下操作:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    //assuming your next view controller class's name is ViewController.
    guard let detailViewController = segue.destination as? ViewController,
        let row = tableView.indexPathForSelectedRow?.row,
        let section = tableView.indexPathForSelectedRow?.section
        else {
            return
    }
    detailViewController.item = dataSource[section][row] //passing selected item object.
}

最后,在下一个视图控制器中,您将获得具有标题和文本属性的item对象。您需要显示其text属性。 希望这对您有帮助!

编辑

完成github上的解决方案。