skip to Main Content

I am using a UITableView and what I am doing is I am changing the color of the cell when I tap on the cell using didSelectRow function of UITableView at cellForRowAt. The thing which is bothering me is when I scroll down or scroll up, those cells whom I changed the color before were changed to other cells. Here is my code:

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

     let cell = myTableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell") as! TasksTableViewCell

     cell.backView.backgroundColor = .white

  return cell
} 

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

  let cell = myTableView.cellForRow(at: indexPath) as! TasksTableViewCell

  cell.backView.backgroundColor = UIColor(named: "primaryViewColor")
} 

Does anyone knows why this happens? Does anyone has a solution that when only those cells changes color whom I tap on, and when I scroll down or move up only those cells have the other color?

5

Answers


  1. So as I understand you select a cell and after that other cells look like they are selected?

    If so I think this is happening because you change the background color of the cell and tableViews and collectionViews are reusing the cells, basically keeping the background you changed behind.

    Login or Signup to reply.
  2. cellForRowAt will be called every time that cell is displayed.
    you need selected list to save selected index.

    var listSelected: [Int] = []
    

    and

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell") as! TasksTableViewCell
        
        cell.backView.backgroundColor = listSelected.contains(indexPath.row) ? UIColor(named: "primaryViewColor") : .white
        
        return cell
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if listSelected.contains(indexPath.row) {
            listSelected = listSelected.filter{$0 != indexPath.row}
        } else {
            listSelected.append(indexPath.row)
        }
        
        tableView.reloadRows(at: [indexPath], with: .automatic)
        
    }
    
    Login or Signup to reply.
  3. TableViewCells are reused as soon as they leave the visible area.
    This means that a cell whose background you have colored will be deleted from the view hierarchy as soon as it is scrolled up or down. If the corresponding row is scrolled in again, the function cellForRowAt is called again for this IndexPath and the cell gets a white background.

    The easiest is to save the IndexPaths of the selected cells and check in the cellForRowAt function if the current cell has to be selected.

    Add the following var to the viewController class:

    var selectedIndexPaths = Set<IndexPath>()
    

    and modify the tableView delegate methods:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell = myTableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell") as! TasksTableViewCell
    
        cell.backView.backgroundColor = (selectedIndexPaths.contains(indexPath) ? UIColor(named: "primaryViewColor") : .white)
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
        if selectedIndexPaths.contains(indexPath)
        {
            selectedIndexPaths.remove(indexPath)
        }
        else
        {
            selectedIndexPaths.insert(indexPath)
        }
        tableView.reloadRows(at: [indexPath], with: .none)
    }
    
    Login or Signup to reply.
  4. I encountered do you see the problem many times. Even if using and iVar can solve the problem, You are mixing "Controller" logic and "Model" logic.

    I usually prefer to move "selection" state inside the model.
    Suppose You have a class "Contact" you use to fill cell data (usual MVC pattern)
    I add:

    class contact{
    ..
    var selected = false
    }
    

    AND in TV delegation method I use to apply selection, OR better I use a custom selection method in a custom cell (for example to see a √ element in cell)
    As a bonus multiple selection come for free, and you can also save current selections for next run 🙂

    Login or Signup to reply.
  5. You can use

    step 1: create model

    class DemoModel {
      var isSelected: Bool = false
      var color: UIColor = .While
     }
    

    step 2: and in tableview

      var listDemo: [DemoModel] = [DemoModel(),...]
    
     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       let cell = myTableView.dequeueReusableCell(withIdentifier: 
       "TasksTableViewCell") as! TasksTableViewCell
        var obj = listDemo[indexPath.row]
       cell.backView.backgroundColor = obj.color
    
       return cell
     } 
    
     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
       var obj = listDemo[indexPath.row]
       obj.color = UIColor(named: "primaryViewColor")
       tableView.reloadRows(at: [indexPath], with: .automatic)
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search