How to prevent UILabel.textColor to change in a de

2019-08-26 17:52发布

问题:

I have this code in my ViewController named PlayViewController:

var words = [String]()

var numberOfRevealedLabels = 1

var indexGA = 0
var indexWA = 0

override func viewDidLoad() {
    super.viewDidLoad()

    playTableView.delegate = self
    playTableView.dataSource = self

    view.isUserInteractionEnabled = true

    let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
    swipeRight.direction = .right
    view.addGestureRecognizer(swipeRight)

    let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
    swipeLeft.direction = .left
    view.addGestureRecognizer(swipeLeft)

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cellIdentifier = "PlayTableViewCell"
    guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? PlayTableViewCell else {
        fatalError("The dequeued cell is not an instance of PlayTableViewCell.")
    }

    cell.wordLabel.text = words[indexPath.row]

    var count = 0
    while (count < words.count)
    {
        if (indexPath.row == count) {
            if (count == 0) {
                cell.wordLabel.isHidden = false
            }
            if (indexGA - 1 == count) {
                cell.wordLabel.textColor = UIColor.green
            } else if (indexWA - 1 == count) {
                cell.wordLabel.textColor = UIColor.red
            }
        }
        count += 1
    }

    cell.wordLabel.isHidden = !(indexPath.row <= numberOfRevealedLabels - 1)

    return cell
}

@objc func respondToSwipeGesture(gesture: UIGestureRecognizer) {
    if let swipeGesture = gesture as? UISwipeGestureRecognizer {
        switch swipeGesture.direction {

        case UISwipeGestureRecognizer.Direction.right:
            indexGA = numberOfRevealedLabels
            numberOfRevealedLabels += 1
            playTableView.reloadData()

        case UISwipeGestureRecognizer.Direction.left:
            indexWA = numberOfRevealedLabels
            numberOfRevealedLabels += 1
            playTableView.reloadData()

        default:
            break
        }
    }
}

So basically, the app does the following stuff:

  • It prompts the first word of the list in black.
  • Swiping right changes the color of the word to green, left to red. Swipes also prompts the next word in black.
  • numberOfRevealedLabels counts the number of words currently displayed, indexGA helps to track the position of the word to turn in green, same for indexWA for the red ones.

When I scroll down to read the next word (I start scrolling at the twelfth word), it's prompted in the same color of the previous word (green if I swiped right or red if left). Also, the first words of the list change their color randomly (either black, green or red).

I've read threads like these ones and I know it's because of dequeueReusableCell.

My code has no else condition. When adding one to set the .textColor to black turns all the words but the last two swiped to black.

To fix the else statement, I can code something like this:

else {
    if (cell.wordLabel.textColor == UIColor.green) {
        cell.wordLabel.textColor = UIColor.green
    } else if (cell.wordLabel.textColor == UIColor.red) {
        cell.wordLabel.textColor = UIColor.red
    } else {
        cell.wordLabel.textColor = UIColor.black
    }
}

Unfortunately, it didn't solve my problem, labels in cells keep changing colors in a weird fashion (plus, it adds a few more ugly LOC to a not so logic loop).

Last thing I've tried: to set wordLabel.textColor = UIColor.blackin PlayTableViewCell.swiftbut it didn't fixed anything.

I'm out of ideas/logic, any help would be very much appreciated!

回答1:

You should set cell.wordLabel.textColor = UIColor.black right after you call cell.wordLabel.text = words[indexPath.row].

So it should look like this:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cellIdentifier = "PlayTableViewCell"
    guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? PlayTableViewCell else {
        fatalError("The dequeued cell is not an instance of PlayTableViewCell.")
    }
    cell.wordLabel.text = words[indexPath.row]
    cell.wordLabel.textColor = UIColor.black //HERE

    var count = 0
    while (count < words.count)
    {
        if (indexPath.row == count) {
            if (count == 0) {
                cell.wordLabel.isHidden = false
            }
            if (indexGA - 1 == count) {
                cell.wordLabel.textColor = UIColor.green
            } else if (indexWA - 1 == count) {
                cell.wordLabel.textColor = UIColor.red
            }
        }
        count += 1
    }

    cell.wordLabel.isHidden = !(indexPath.row <= numberOfRevealedLabels - 1)

    return cell
}

Adding an else doesn't solve the problem because it's placed in a nested if statement. A cell with the color can still be reused since you aren't setting a default color before any if statements. Adding it outside of all if statements will ensure the color is always black unless a condition is met.