14wml
14wml

Reputation: 4166

When select cell, UITableView changing appearance when scroll?

I have the strangest glitch after I select a UITableView cell and scroll away(You can see it here):

When I select a cell, it's programmed to change its text and change the font color from brown to red. However, when I scroll, other cells that I have not selected change their font color to red. And when I scroll back to the selected cell it reverts to its original text and sometimes, its font color too (from red to brown).

I've used this post in attempt to fix it. But still the glitch remains.

I am completely baffled as to why this is happening and would love love love if anyone could tell me why.

In my code I made my ViewController CategoryViewController the UITableView's Datasource & Delegate instead of a UITableViewController b/c I have other views in my CategoryViewController, not just a UITableView

class CategoryViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    private let themeColors = ThemeColors()
    private let expensesOrganizer = ExpensesOrganizer()

    override func viewDidLoad() {
        super.viewDidLoad()

        //Set up subCategory table view
        subCategoryTableView.dataSource = self
        subCategoryTableView.delegate = self
    }

    // MARK: UITableViewDataSource

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return expensesOrganizer.getNumOfSubcategoriesFor(category!)
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let subcategoryCell = tableView.dequeueReusableCellWithIdentifier("subCategoryCell", forIndexPath: indexPath) as! SubcategoryTableViewCell
        let subcategory = expensesOrganizer.getSubcategoryFor(category!, index: indexPath.row)
        subcategoryCell.subCategoryLabel.text = "\(indexPath.row) \(expensesOrganizer.getText(subcategory.rawValue))"
        subcategoryCell.selectedBackgroundView = UIView(frame: CGRect.zero)
        subcategoryCell.selectedBackgroundView?.backgroundColor = themeColors.getColorOfCategory(category!)

        return subcategoryCell
    }

    // MARK: UITableViewDelegate

    var indexPathSelectedCell: NSIndexPath?

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let subcategoryCell = tableView.cellForRowAtIndexPath(indexPath) as! SubcategoryTableViewCell
        subcategoryCell.subCategoryLabel.textColor = UIColor.redColor()
        subcategoryCell.subCategoryLabel.text = "\(indexPath.row) didSELECTRowAtIndexPath called"
        indexPathSelectedCell = indexPath

       //What the post said to add:
        let selectedRows = subCategoryTableView.indexPathsForSelectedRows
        for i in selectedRows! {
            if !i.isEqual(indexPath){
                subCategoryTableView.deselectRowAtIndexPath(i, animated: false)
            }
        }
    }

    func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
        let subcategoryCell = tableView.cellForRowAtIndexPath(indexPath) as! SubcategoryTableViewCell
        subcategoryCell.subCategoryLabel.textColor = themeColors.getFontColor(Shade.Light)
        subcategoryCell.subCategoryLabel.text = "\(indexPath.row) didDESELECTRowAtIndexPath called"
    }

Upvotes: 0

Views: 1478

Answers (2)

user4151918
user4151918

Reputation:

This has to do with cell reuse.

When you change the color of the label in didSelectRowAtIndexPath, then scroll that cell off-screen, it gets reused for a different cell that will appear on-screen.

However, since you don't prepare the cell for reuse, it is still using the selected font color for your label.

Assigning the label's default text color in prepareForReuse or cellForRowAtIndexPath will fix this issue.

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727077

The approach that you take is incorrect, because you are not setting the color when you reuse a cell. Your cellForRowAtIndexPath needs to set color back to brown if the cell is not selected. It should be set to red if the cell is selected:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let subcategoryCell = tableView.dequeueReusableCellWithIdentifier("subCategoryCell", forIndexPath: indexPath) as! SubcategoryTableViewCell
    let subcategory = expensesOrganizer.getSubcategoryFor(category!, index: indexPath.row)
    subcategoryCell.subCategoryLabel.text = "\(indexPath.row) \(expensesOrganizer.getText(subcategory.rawValue))"
    subcategoryCell.selectedBackgroundView = UIView(frame: CGRect.zero)
    subcategoryCell.selectedBackgroundView?.backgroundColor = themeColors.getColorOfCategory(category!)
    if let selected = tableView.indexPathsForSelectedRows() as? [NSIndexPath] && selected! == indexPath {
        subcategoryCell.subCategoryLabel.textColor = UIColor.brownColor()            
    } else {
        subcategoryCell.subCategoryLabel.textColor = UIColor.redColor()
    }
    return subcategoryCell
}

Upvotes: 2

Related Questions