Ios 具有多节数组和行数据数组搜索实现的Swift UITableview自定义单元格

Ios 具有多节数组和行数据数组搜索实现的Swift UITableview自定义单元格,ios,swift,Ios,Swift,在我的场景中,我尝试创建带有多个节和单元格的UITableview自定义单元格。在这里,我想添加两件事复选标记和search选项,这两件事我都尝试过使用下面的代码,但都不起作用 下面是我的代码。如何解决这个问题 class CustomCell: UITableViewCell { @IBOutlet weak var NameLabel: UILabel! @IBOutlet weak var CountLabel: UILabel! override func

在我的场景中,我尝试创建带有多个节和单元格的
UITableview
自定义单元格。在这里,我想添加两件事复选标记和
search
选项,这两件事我都尝试过使用下面的代码,但都不起作用

下面是我的代码。如何解决这个问题

class  CustomCell: UITableViewCell {

    @IBOutlet weak var NameLabel: UILabel!
    @IBOutlet weak var CountLabel: UILabel!

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        self.accessoryType = selected ? .checkmark : .none
    }
}


class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {

    var searchController : UISearchController!
    let sectionData = ["1", "2"]
    let rowNames = [["A", "B", "C"], ["D", "E", "F"]]
    var filteredData: [[String]]!
    let cellReuseIdentifier = "cell"
    @IBOutlet var tableView: UITableView!


override func viewDidLoad() {
        super.viewDidLoad()
        filteredData = rowNames
}


//MARK: List Tableview
    func numberOfSections(in tableView: UITableView) -> Int {
        return sectionData.count
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sectionData[section]
    }

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell:CustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! CustomCell
        cell.NameLabel.text = filteredData[indexPath.section][indexPath.row]
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.tableView.deselectRow(at: indexPath, animated: true)
    }

//MARK: Search Delegate

func updateSearchResults(for searchController: UISearchController) {
        if let searchText = searchController.searchBar.text {
            filteredData = searchText.isEmpty ? rowNames : rowNames.filter({(dataString: String) -> Bool in
                return dataString.range(of: searchText, options: .caseInsensitive) != nil
            })
            Self.tableView.reloadData()
        }
    }
}

我强烈建议你更换

let sectionData = ["1", "2"]
let rowNames = [["A", "B", "C"], ["D", "E", "F"]]

filteredData
声明为
[String:[String]]?
,而不是
[[String]]

然后,您可以使用以下代码过滤
tableViewData

filteredData = tableViewData.compactMapValues { currentSection -> [String]? in
    let filteredRow = currentSection.filter {
        $0.range(of: searchText, options: .caseInsensitive) != nil
    }
    return filteredRow.isEmpty ? nil : filteredRow
}
添加新属性
var Filteredatakeys:[字符串]?
并在每次更新
Filteredata
后更新它:
Filteredatakeys=Filteredata?.keys.sorted()

并使用以下
UITableViewDataSource
方法:

func numberOfSections(in tableView: UITableView) -> Int {
    return filteredDataKeys?.count ?? 0
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return filteredDataKeys?[section]
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    guard let keyForSection = filteredDataKeys?[section] else {
        return 0
    }
    return filteredData?[keyForSection]?.count ?? 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! CustomCell
    guard let keyForSection = filteredDataKeys?[indexPath.section] else {
        return cell
    }
    let textForRow = filteredData?[keyForSection]?[indexPath.row]
    cell.NameLabel.text = textForRow
    return cell
}

我强烈建议你更换

let sectionData = ["1", "2"]
let rowNames = [["A", "B", "C"], ["D", "E", "F"]]

filteredData
声明为
[String:[String]]?
,而不是
[[String]]

然后,您可以使用以下代码过滤
tableViewData

filteredData = tableViewData.compactMapValues { currentSection -> [String]? in
    let filteredRow = currentSection.filter {
        $0.range(of: searchText, options: .caseInsensitive) != nil
    }
    return filteredRow.isEmpty ? nil : filteredRow
}
添加新属性
var Filteredatakeys:[字符串]?
并在每次更新
Filteredata
后更新它:
Filteredatakeys=Filteredata?.keys.sorted()

并使用以下
UITableViewDataSource
方法:

func numberOfSections(in tableView: UITableView) -> Int {
    return filteredDataKeys?.count ?? 0
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return filteredDataKeys?[section]
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    guard let keyForSection = filteredDataKeys?[section] else {
        return 0
    }
    return filteredData?[keyForSection]?.count ?? 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! CustomCell
    guard let keyForSection = filteredDataKeys?[indexPath.section] else {
        return cell
    }
    let textForRow = filteredData?[keyForSection]?[indexPath.row]
    cell.NameLabel.text = textForRow
    return cell
}

我建议做一些这样的修改

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {

var searchController : UISearchController!
var rowNames = [[(value: "A",selected: false),(value: "B",selected: false),(value:"C",selected:false)],[(value: "D",selected: false),(value: "E",selected:false),(value:"F",selected:false)]]
var filteredData: [[(value:String,selected:Bool)]]!
let cellReuseIdentifier = "cell"
@IBOutlet var tableView: UITableView!


override func viewDidLoad() {
    super.viewDidLoad()
    //filteredData = rowNames
}


//MARK: List Tableview
func numberOfSections(in tableView: UITableView) -> Int {
    return rowNames.count
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return (section + 1).description
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if searchController.searchBar.text != nil && searchController.searchBar.text != ""{
        return filteredData.count
    }else{
        return rowNames[section].count
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell:CustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! CustomCell
    if searchController.searchBar.text != nil && searchController.searchBar.text != ""{
         cell.NameLabel.text = filteredData[indexPath.section][indexPath.row].value
    }else{
        cell.NameLabel.text =  rowNames[indexPath.section][indexPath.row].value
    }

    return cell
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath)
    if searchController.searchBar.text == nil || searchController.searchBar.text == ""{
        if rowNames[indexPath.section][indexPath.row].selected == true{
            cell?.accessoryType = .none
            rowNames[indexPath.section][indexPath.row].selected = false
        }else{
            cell?.accessoryType = .checkmark
            rowNames[indexPath.section][indexPath.row].selected = true
        }
    }

    //self.tableView.deselectRow(at: indexPath, animated: true)
}

//MARK: Search Delegate

func updateSearchResults(for searchController: UISearchController) {
    if let searchText = searchController.searchBar.text, searchController.searchBar.text != "" {
        })
      filteredData =  rowNames.map({row in
            row.filter({
                $0.value.contains(searchText)
            }).map({$0})
        })
        self.tableView.reloadData()
    }
}
} 由于要在选定的单元格上设置复选标记,因此必须在数据源中跟踪该单元格的状态。这就是为什么如果你使用一个结构,模型会变成一个元组,你可以添加一个sleceted字段,并且在你的


didSelectRow功能您必须跟踪模型的状态才能显示或不显示复选标记。搜索不值得搜索,因为没有用于搜索的文本,因此应用程序不应重新加载tableView。

我建议进行一些类似的更改

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {

var searchController : UISearchController!
var rowNames = [[(value: "A",selected: false),(value: "B",selected: false),(value:"C",selected:false)],[(value: "D",selected: false),(value: "E",selected:false),(value:"F",selected:false)]]
var filteredData: [[(value:String,selected:Bool)]]!
let cellReuseIdentifier = "cell"
@IBOutlet var tableView: UITableView!


override func viewDidLoad() {
    super.viewDidLoad()
    //filteredData = rowNames
}


//MARK: List Tableview
func numberOfSections(in tableView: UITableView) -> Int {
    return rowNames.count
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return (section + 1).description
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if searchController.searchBar.text != nil && searchController.searchBar.text != ""{
        return filteredData.count
    }else{
        return rowNames[section].count
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell:CustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! CustomCell
    if searchController.searchBar.text != nil && searchController.searchBar.text != ""{
         cell.NameLabel.text = filteredData[indexPath.section][indexPath.row].value
    }else{
        cell.NameLabel.text =  rowNames[indexPath.section][indexPath.row].value
    }

    return cell
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath)
    if searchController.searchBar.text == nil || searchController.searchBar.text == ""{
        if rowNames[indexPath.section][indexPath.row].selected == true{
            cell?.accessoryType = .none
            rowNames[indexPath.section][indexPath.row].selected = false
        }else{
            cell?.accessoryType = .checkmark
            rowNames[indexPath.section][indexPath.row].selected = true
        }
    }

    //self.tableView.deselectRow(at: indexPath, animated: true)
}

//MARK: Search Delegate

func updateSearchResults(for searchController: UISearchController) {
    if let searchText = searchController.searchBar.text, searchController.searchBar.text != "" {
        })
      filteredData =  rowNames.map({row in
            row.filter({
                $0.value.contains(searchText)
            }).map({$0})
        })
        self.tableView.reloadData()
    }
}
} 由于要在选定的单元格上设置复选标记,因此必须在数据源中跟踪该单元格的状态。这就是为什么如果你使用一个结构,模型会变成一个元组,你可以添加一个sleceted字段,并且在你的



didSelectRow功能您必须跟踪模型的状态才能显示或不显示复选标记。搜索不值得搜索,因为没有搜索文本,因此应用程序不应重新加载tableView。

sectionData=Filteredata before tableView.reloadData()@AlexandrKolesnik我遇到错误-类型“[String]”的值在返回数据字符串时没有成员“range”。range(of:searchText,options:.Case不区分大小写)!=零线。另外,我想为这个使用更好的代码。datastring.lowercased().contains(searchText.lowercased())filteredData=searchText.isEmpty?projects:projects.filter({(dataString:[String])->Bool in return dataString.lowercased().contains(searchText.lowercased())})显示类型“[String]”的错误值没有成员“lowercased”@AlexandrKolesnikin问题您的dataString:String在注释dataString:[String]中它对搜索很重要,对于数组,您应该执行类似smth的数据字符串。首先(其中:{$0.lowercased().contains(searchText.lowercased())})sectionData=Filteredata before tableView.reloadData()@AlexandrKolesnik我面临错误-类型“[String]”的值在返回数据字符串时没有成员“range”。range(of:searchText,选项:.CaseSensitive)!=零线。另外,我想为这个使用更好的代码。datastring.lowercased().contains(searchText.lowercased())filteredData=searchText.isEmpty?projects:projects.filter({(dataString:[String])->Bool in return dataString.lowercased().contains(searchText.lowercased())})显示类型“[String]”的错误值没有成员“lowercased”@AlexandrKolesnikin问题您的dataString:String在注释dataString:[String]中它对搜索很重要,对于数组,您应该先执行类似于smth的dataString.first(其中:{$0.lowercased().contains(searchText.lowercased())}),这是一个很好的解决方案。顺便说一句,您可以使用Struct进行更新,因为我将在将来用于此JSON数据加载@Roman PodymovThanks@Roman Podymov顺便说一句,我们不能在numberofrows guard let keyForSection=Filteredata?.keys.sorted()[indexPath.section]中分配return 0,否则{return 0}@BenDev为什么不能?据我所知,如果
searchText==“G”
表中将没有行。让我们来看看。感谢老兄,这是一个很好的解决方案。顺便说一句,您可以使用Struct进行更新,因为我将在将来用于此JSON数据加载@Roman PodymovThanks@Roman Podymov顺便说一句,我们不能在numberofrows guard let keyForSection=Filteredata?.keys.sorted()[indexPath.section]中分配return 0,否则{return 0}@BenDev为什么不能?据我所知,如果
searchText==“G”
表中将没有行。让我们。我认为section.description缺少@kjoeThanks,我将检查它。但我仍然没有得到完美的答案,因为我要加载JSON数据,所以如果有人使用带解释的struct。@kjoeman会更好,然后你应该发布一个带有struc和json struc而不是相对数据的问题,你想要一个不问问题的答案,尝试在github中发布一个MVP以进行分类,因为这段代码几乎是带有struc和jsonI think section.description的代码的一部分。缺少@kjoeThanks我会检查它。但我仍然没有得到完美的答案,因为我要加载JSON数据,所以如果有人使用带解释的struct。@kjoeman会更好,然后你应该发布一个带有struc和json的问题struc而不是相对数据,你想要一个不问问题的答案,试着在github中发布一个MVP进行分类,因为这段代码几乎是带有struc和json的代码的一部分