Louis Brahmi
Louis Brahmi

Reputation: 862

tableViewCell wrong background Color

I have a tableView assigned to my ShopViewController this controller called the ShopCellClass to draw programmatically each row of the tableView. The ShopCellClass called my shopClass to know how many item sell.

The problem is in my shopClass I have a UIColor to assign in the background of the cell but the last cell don't have the right color.

I show you the code of my 3 files:

ShopViewController :

class ShopViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

@IBOutlet var tableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.register(ShopCellClass.self, forCellReuseIdentifier: "CellShop")
    tableView.rowHeight = 155
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return shop.data.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier:"CellShop") as! ShopCellClass
    cell.drawTheCard(index: indexPath.row)
    return cell
}
}

ShopCellClass :

class ShopCellClass : UITableViewCell {

var widthOfCard : CGFloat = 0
var heightOfCard : CGFloat = 0
var cardIsDraw : Bool = false

let cardView = UIView()

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    self.contentView.addSubview(cardView)
    widthOfCard = UIScreen.main.bounds.size.width
    heightOfCard = 155
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

func drawTheCard(index : Int){
    if(cardIsDraw == false){
        drawCard(index: index)
        cardIsDraw = true
    }
}

private func drawCard(index: Int){
    cardView.frame = CGRect(x : 0, y : 0, width : widthOfCard, height : heightOfCard)
    cardView.backgroundColor = shop.data[index].color
}
}

and ShopClass :

class ShopClass {
    var data: [(id : Int, name : String, price : Double, color : UIColor)] = []

    init(){
        self.loadShopData()
    }

    func loadShopData(){
        data.append((id : 1, name : "Pack 1", price : 4.99, color : UIColor(rgb: 0xE08B37)))
        data.append((id : 2, name : "Pack 2", price : 9.99, color : UIColor(rgb: 0xAFAFAF)))
        data.append((id : 3, name : "Pack 3", price : 15.99, color : UIColor(rgb: 0xF3CD00)))
        data.append((id : 4, name : "Pack 4", price : 19.99, color : UIColor(rgb: 0xF20000)))
        data.append((id : 5, name : "Pack 5", price : 24.99, color : UIColor(rgb: 0x000000))) 
    }
}

let shop = ShopClass()

the render :

The last color is brown but normally black.

Where did I go wrong?

Upvotes: 0

Views: 224

Answers (2)

Grzegorz Krukowski
Grzegorz Krukowski

Reputation: 19792

Quick answer - remove this check from your code:

if(cardIsDraw == false){

Longer answer with explanation:

You assumed that there will be ShopCellClass class created for each row which is completely wrong. UITableView is optimizing drawing by creating only as many Cell classes as absolutely necessary (usually as many as rows visible at once on screen). When you start scrolling instances that dissapear from the screen (they are moved outside of visible area) are being reused and same instances are used to display new one.

That's why you see new cell being brown - because it's reusing instance of first row - and due to your check for if(cardIsDraw == false){ the code for changing color is not executed. It's easy to fix in your case - but it's really important to understand that mechanics as lot's of people are getting caught by this keeping also some important parts of their data model in those cells.

You can read more about it here: https://developer.apple.com/documentation/uikit/uitableview/1614878-dequeuereusablecell

and here: https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html

Upvotes: 1

Shehata Gamal
Shehata Gamal

Reputation: 100503

Because of dequeuing this var

var cardIsDraw : Bool = false

is changed to true , so when the last one show it dequeues top brown one where the var is true so this

if(cardIsDraw == false){
    drawCard(index: index)
    cardIsDraw = true
}

won't run which cause the color to remain brown and not to change to black , so completely remove the if statement and the var

Upvotes: 1

Related Questions