Ziyaad
Ziyaad

Reputation: 55

Multiple Cell Selection on TableView

I'm having an issue where when I'm selecting the cell for e.g 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
}

}

Upvotes: 3

Views: 679

Answers (4)

Dharmesh Mansata
Dharmesh Mansata

Reputation: 4738

Make bool array for stability while scrolling i.e.

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!

Upvotes: 1

PPL
PPL

Reputation: 6565

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)
}

Upvotes: 3

Zoeb S
Zoeb S

Reputation: 705

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 :-)

Upvotes: 0

Reinier Melian
Reinier Melian

Reputation: 20804

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

enter image description here

Upvotes: 0

Related Questions