带搜索栏和复选标记的Swift UItableview

时间:2014-11-20 16:53:51

标签: ios uitableview swift searchbar checkmark

我一直在尝试使用复选标记在UITableView上执行SearchBar。用户可以一次只勾选一个。我设法做了勾选和搜索。但是当我搜索并勾选搜索结果时,就是它开始失败的地方

import UIKit

class CandyTableViewController : UITableViewController, UISearchBarDelegate, UISearchDisplayDelegate {

    var lastSelectedIndexPath = NSIndexPath(forRow: 0, inSection: 0)

    var candies = [Candy]()
    var mySelected=String()


    var filteredCandies = [Candy]()

    override func viewDidLoad() {
        self.candies = [Candy(category:"Chocolate", name:"chocolate Bar"),
            Candy(category:"Chocolate", name:"chocolate Chip"),
            Candy(category:"Chocolate", name:"dark chocolate"),
            Candy(category:"Hard", name:"lollipop"),
            Candy(category:"Hard", name:"candy cane"),
            Candy(category:"Hard", name:"jaw breaker"),
            Candy(category:"Other", name:"caramel"),
            Candy(category:"Other", name:"sour chew"),
            Candy(category:"Other", name:"gummi bear")]

        mySelected=candies[lastSelectedIndexPath.row].name

    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if tableView == self.searchDisplayController!.searchResultsTableView {
            return self.filteredCandies.count
        } else {
            return self.candies.count
        }
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell

        cell.accessoryType = .Checkmark


        var candy : Candy
        if tableView == self.searchDisplayController!.searchResultsTableView {
            candy = filteredCandies[indexPath.row]

        } else {
            candy = candies[indexPath.row]

        }

        if mySelected==candy.name {
            cell.accessoryType = .Checkmark
            lastSelectedIndexPath=indexPath
        } else {
            cell.accessoryType = .None
        }

        cell.textLabel.text = candy.name

        return cell
    }

    func filterContentForSearchText(searchText: String, scope: String = "All") {
        self.filteredCandies = self.candies.filter({( candy : Candy) -> Bool in
            var categoryMatch = (scope == "All") || (candy.category == scope)
            var stringMatch = candy.name.rangeOfString(searchText)
            return categoryMatch && (stringMatch != nil)
            })
    }

    func searchDisplayController(controller: UISearchDisplayController!, shouldReloadTableForSearchString searchString: String!) -> Bool {
        let scopes = self.searchDisplayController!.searchBar.scopeButtonTitles as [String]
        let selectedScope = scopes[self.searchDisplayController!.searchBar.selectedScopeButtonIndex] as String
        self.filterContentForSearchText(searchString, scope: selectedScope)
        return true
    }

    func searchDisplayController(controller: UISearchDisplayController!,
        shouldReloadTableForSearchScope searchOption: Int) -> Bool {
            let scope = self.searchDisplayController!.searchBar.scopeButtonTitles as [String]
            self.filterContentForSearchText(self.searchDisplayController!.searchBar.text, scope: scope[searchOption])
            return true
    }

    func searchDisplayController(controller: UISearchDisplayController, willHideSearchResultsTableView tableView: UITableView) {
        self.tableView.reloadData()
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

        tableView.deselectRowAtIndexPath(indexPath, animated: true)

       if indexPath.row != lastSelectedIndexPath?.row {
            if let lastSelectedIndexPath = lastSelectedIndexPath {
                let oldCell = tableView.cellForRowAtIndexPath(lastSelectedIndexPath)
                oldCell?.accessoryType = .None
            }
            let newCell = tableView.cellForRowAtIndexPath(indexPath)
            newCell?.accessoryType = .Checkmark
            lastSelectedIndexPath = indexPath
            mySelected = newCell?.textLabel.text ?? ""


      }

        if candies[indexPath.row].name != candies[lastSelectedIndexPath.row].name {

                let oldCell = tableView.cellForRowAtIndexPath(lastSelectedIndexPath)
                oldCell?.accessoryType = .None
            }

            let newCell = tableView.cellForRowAtIndexPath(indexPath)
            newCell?.accessoryType = .Checkmark

            lastSelectedIndexPath = indexPath

            mySelected = newCell?.textLabel.text ?? ""


    }

  }

我希望它能够在搜索后进行复选标记。返回完整列表时,请保持这种状态。请帮助,我已经尝试解决这个问题几天了。

更新:我设法按预期执行。但相信代码可以比这更简单

2 个答案:

答案 0 :(得分:2)

您有一个要修复的错误,然后进行一些更改以使搜索结果中的选择显示在常规表视图中。

首先,错误 - 在tableView:didSelectRowAtIndexPath:中,您正在设置myselected,如下所示:

myselected=candies[indexPath.row].name

在常规表视图中工作正常,但在搜索结果中,indexPath.row未指向candies数组的右侧成员。由于您要跟踪糖果的名称,只需从选定的行中取回名称:

myselected = newCell?.textLabel?.text ?? ""

如果使用此更改运行代码,则不会发现任何差异,因为搜索后您没有重新加载主表视图。为此,请实现委托方法searchDisplayController:willHideSearchResultsTableView:

func searchDisplayController(controller: UISearchDisplayController, willHideSearchResultsTableView tableView: UITableView) {
    self.tableView.reloadData()
}

几乎就在那里!为表格视图配置单元格时,您将向当前单元格添加复选标记,但不会将其从其他单元格中清除。稍微更改您的代码:

if myselected==candy.name {
    cell.accessoryType = .Checkmark
    lastSelectedIndexPath=indexPath
} else {
    cell.accessoryType = .None
}

答案 1 :(得分:0)

解决方案有点棘手。其中一个问题由@Nate Cook解决:

mySelected = newCell?.textLabel.text ?? ""

第二个问题是在搜索模式和正常模式下正确取消选择。您需要了解NSIndexPath是您的情况的动态值。 E.g:

正常模式下的表(index = indexPath.row)

+-------+------+
| Index | Name |
+-------+------+
|     0 | A    |
|     1 | B    |
|     2 | C    |
|     3 | BB   |
+-------+------+

例如,我们选择了第4行,现在我们已经lastSelectedIndexPath = 3了。如果选择新行,则代码将使用lastSelectedIndexPath正确取消选择行。

但是......让我们看看当您使用关键字 B 激活搜索时会发生什么。

+-------+------+
| Index | Name |
+-------+------+
|     0 | B    |
|     1 | BB   |
+-------+------+

查看索引,他们改变了!现在,当您尝试选择名称为 B 的行时,您的脚本会尝试取消选择lastIndexPath = 3行。但是没有这种索引的行,因为你有完全新的索引。

那么我们能做什么?每当UITableView使用Checkmark制作单元格时,我们都可以重新生成lastIndexPath。你已经做到了,这是正确的解决方案,我只是描述了更详细的内容(你在没有描述的情况下改变了你的代码)。

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        // cutted some code
        cell.accessoryType = .Checkmark
        lastSelectedIndexPath=indexPath
}

如果您只有一个复选标记,则代码是最简单的解决方案。如果您需要存储多个复选标记,则需要编写更复杂的代码。这个问题只是关于使用searchController存储1个复选标记。