mugiwara528
mugiwara528

Reputation: 381

UITableViewCell only displays accessory after scrolling

So I have a TableView with custom cells that I make from fetching data from a server. I have a variable 'selectedIndex' which I use to keep track and add a checkmark accessory to my cell. Weirdly, it only works after I scroll the selected cell (cell with indexPath.row is equal to off the screen and back. Here is the code in my willDisplayCell method:

if selectedIndex == indexPath.row {
    if let accessory = cell.viewWithTag(528) as? UITableViewCell {
        accessory.frame = (cell.checkmarkView.bounds.offsetBy(dx: 0, dy: 7))
        accessory.accessoryType = .checkmark
        accessory.isUserInteractionEnabled = false
        accessory.backgroundColor = UIColor.clear
        accessory.tag = 528
        accessory.isHidden = false
        print("accessory not nil")
     } else {
        let accessory = UITableViewCell()
        accessory.frame = (cell.checkmarkView.bounds.offsetBy(dx: 0, dy: 7))
        accessory.accessoryType = .checkmark
        accessory.isUserInteractionEnabled = false
        accessory.backgroundColor = UIColor.clear
        accessory.tag = 528
        accessory.isHidden = false
        cell.addSubview(accessory) 
        print("accessory nil")        
     }
 } else {
     let accessory = cell.viewWithTag(528)
     accessory?.isHidden = true
 }

For example, when the selected index is 0, the checkmark is not displayed at first view, and the logs print ("accessory nil"). When I scroll the cell at index 0 off-screen, and scroll to it again, the checkmark is now displayed and the logs print ("accessory not nil"). For more information, tapping on a cell works just as expected.

Edit:

  1. I know I'm adding another TableViewCell to my cell! I'm only doing that because I need my checkmark accessory to be in a different position (left-aligned, top-aligned) than the default one (right-aligned, vertically centered). So what I did was add a view in my XIB that is in the desired position (right-aligned, top-aligned) and and aligned my programatically-made cell to it. If you could show me another approach it would be appreciated.

  2. Removed cell.addSubview from the first if. Still behaves the same.

Thanks!

Upvotes: 1

Views: 477

Answers (2)

Reinier Melian
Reinier Melian

Reputation: 20804

You are adding UITableViewCell into your dequeued original cell, this is unnecessary, you need implement this logic in your cellForRowAt datasource method,

updated

If you need a custom position for your accessory view use cell.layoutMargins check my updated code

try this instead

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier", for: indexPath) as! YourCellClass
    
        cell.accessoryType = .none
        if selectedIndex == indexPath.row {
              cell.accessoryType = .checkmark
        }
        //if you need a custom position for your accessory view
        cell.layoutMargins = UIEdgeInsetsMake(0, 0, 0, 100)
    }

enter image description here

Upvotes: 1

Aron K.
Aron K.

Reputation: 350

UITableView will optimize your cells by reusing them. So in your case it seems better to use tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) instead of calling the Cell's constructor yourself or find the cell back by looking for it's tag.

Besides that the part which determines the state of the cell should be in the UITableView's tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell function instead of the willDisplayCell. This might solve your problem and prevents issues with reusing cells.

Upvotes: 0

Related Questions