简体   繁体   中英

Multiple Cell Selection on TableView

I'm having an issue where when I'm selecting the cell for eg at index 3 , it selecting cells below also at random indexes. Check and Uncheck cell is working but for some reasons when selecting a cell it is selecting other cells as well. My array is returning 120 rows in total. I have selected multiple touch. Thank you for the help.

 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{

    return arrayVerbCount.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{

    let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MesTalentsChoixCell

    cell.verb!.text = arrayVerbCount[indexPath.row].verb

    if cell.isSelected
    {
        cell.isSelected = false
        if cell.accessoryType == UITableViewCellAccessoryType.none
        {
            cell.accessoryType = UITableViewCellAccessoryType.checkmark
        }
        else
        {
            cell.accessoryType = UITableViewCellAccessoryType.none
        }
    }

    return cell
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){

    let cell = tableView.cellForRow(at: indexPath)

    if cell!.isSelected
    {
        cell!.isSelected = false
        if cell!.accessoryType == UITableViewCellAccessoryType.none
        {
            cell!.accessoryType = UITableViewCellAccessoryType.checkmark
        }
        else
        {
            cell!.accessoryType = UITableViewCellAccessoryType.none
        }
    }
}

My custom cell class:

class MesTalentsChoixCell: UITableViewCell {

@IBOutlet weak var verb: UILabel!

override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
}

}

You should do like this way, this is very much easy solution if there is only one section.

Initialize selectedItems array like this,

var selectedItems: [Int] = []

Find UITableViewDataSource method below

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
    cell.tmpValue.text = data[indexPath.row]

    if selectedItems.contains(indexPath.row) {
        cell.accessoryType = .checkmark
    } else {
        cell.accessoryType = .none
    }

    return cell
}

Find UITableViewDelegate Method below.

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

    if selectedItems.contains(indexPath.row) {
        let index = selectedItems.index(of: indexPath.row)
        selectedItems.remove(at: index!)
    } else {
        selectedItems.append(indexPath.row)
    }

    tableView.reloadRows(at: [indexPath], with: .none)
}

Code will be changed depending on your requirement and custom cell. Hope you can do it your way. Thank you.

UPDATE

You can even use Set also like this way,

var setSelectedItems: Set<Int> = []

UITableViewDataSource method,

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
    cell.tmpValue.text = data[indexPath.row]

    if setSelectedItems.contains(indexPath.row) {
        cell.accessoryType = .checkmark
    } else {
        cell.accessoryType = .none
    }

    return cell
}

UITableViewDelegate method,

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

    if setSelectedItems.contains(indexPath.row) {
        setSelectedItems.remove(indexPath.row)
    } else {
        setSelectedItems.insert(indexPath.row)
    }
    tableView.reloadRows(at: [indexPath], with: .none)
}

Make bool array for stability while scrolling ie

var arrStatusBool = [Bool]()

Now set value at indexPath.row in didSelectRowAt

public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
{
    if self.arrStatusBool[indexPath.row]
    {
        self.arrStatusBool[indexPath.row] = false
    } 
    else 
    {
        self.arrStatusBool[indexPath.row] = true
    }
}

And also put this in cellForRowAt to avoid scrolling issue.

if self.arrStatusBool[indexPath.row]
{
     tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
} 
else 
{
    tableView.cellForRow(at: indexPath)?.accessoryType = .none
}

hope this help!

For multiple selection you should track selected cells in a Dictionary for convenience faster access to selected and unselected indexPaths allowing you use multiple sections because the key value of our Dictionary is a string formed by (IndexPath.section)+(IndexPath.row) which is always unique combination

var selectedIndexPaths : [String:Bool] = [:]

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    let currentIndexPathStr = "\(indexPath.section)\(indexPath.row)"
    if(self.selectedIndexPaths[currentIndexPathStr] == nil || !self.selectedIndexPaths[currentIndexPathStr]!) {
        self.selectedIndexPaths[currentIndexPathStr] = true
    }else{
        self.selectedIndexPaths[currentIndexPathStr] = false
    }
    self.tableView.reloadRows(at: [indexPath], with: .automatic)
}


public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "npCell", for: indexPath) as! NewPlaylistTableViewCell

        cell.mTitle.text = musics[indexPath.row]["title"] as! String?
        cell.mArtist.text = musics[indexPath.row]["artist"] as! String?

        cell.accessoryType = .checkmark
        let currentIndexPathStr = "\(indexPath.section)\(indexPath.row)"
        if(self.selectedIndexPaths[currentIndexPathStr] == nil || !self.selectedIndexPaths[currentIndexPathStr]!)  {
           cell.accessoryType = .none
        }

        return cell
    }

Results

在此处输入图片说明

Just a minor change

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{

    let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MesTalentsChoixCell

    cell.verb!.text = arrayVerbCount[indexPath.row].verb

    if cell.isSelected
    {
       cell.accessoryType = UITableViewCellAccessoryType.checkmark
    }
    else
    {
       cell.accessoryType = UITableViewCellAccessoryType.none
    }

    return cell
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){

    let cell = tableView.cellForRow(at: indexPath)

    //toggle the state
    cell!.isSelected = !cell!.isSelected

    if cell!.isSelected
    {
        cell!.accessoryType = UITableViewCellAccessoryType.checkmark 
    }
    else
    {
        cell!.accessoryType = UITableViewCellAccessoryType.none
    }
}

Note: you should also create method for common code :-)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM