Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 8 Swift UICollectionView reloadData() causing views (images) to jump cells

I have a UICollectionView of 20 cells with an imageView inside of them. when a user clicks on the correct cell, I draw another imageView in that cell (a correctCircle let's call it). This works fine.

But I also have a header in the UICollectionView where I ask the question they need to answer. After each click (wait 2 secs) the question should be updated, I have a function that updates the label for the Header text, this also works fine.

My problem is: In order to update the Header text, I have to call uicollectionView.reloadData() and whenever I do that, the UIImageView that I drew in the cell (the correctCircle) gets moved to another cell!

I've tried everything I can think of, including solutions in this thread: UICollectionView reloadData not functioning properly in iOS 7

But can't get it to work. Any ideas are more than welcome. Ideally I would only refresh the header and not the rest of the cells but there doesn't seem to be a way to do that.

Edit: slightly altering code based on comments, now I have 2 images in each cell and one is hidden, then I show it, instead of adding an imageView upon click.

Here's some relevant code:

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as CollectionViewIconCell    

        // bigIcon() just returns the animal's icon image
        cell.icon.image = animalsArray[indexPath.row].bigIcon()

        return cell
    }

override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        // we cannot use a dequeueReusableCellWithReuseIdentifier, we need this
        let cell = collectionView.cellForItemAtIndexPath(indexPath) as CollectionViewIconCell

        if currentAnimal == self.correctAnimal {
            cell.circleImage.image = correctCircleImage
            cell.circleImage.hidden = false

            correctAnswers++

            // nextQuestion() simply loads the text that will go in the Header.label
            self.nextQuestion()
            self.collectionView!.reloadData()

        } else {
            self.answerCircle.image = UIImage(named: "wrongCircle")
            self.answerCircle.sizeToFit()
            cell.addSubview(answerCircle)

            self.nextQuestion()
            self.collectionView!.reloadData()
        }        
    }

Thanks.

PS

Reading some of the comments, maybe I'm not setting the text for the header correctly on a new question? I got all this code from tutorials, very new to UICollectionView so excuse my ignorance but is there a better way to refresh the header text? I can't get the header outside of the viewForSupplementaryElementOfKind function.

I should explain I have 2 different imageViews, one for correct answer and one for wrong answer because the circe for correct answer should remain while the one for wrong answer will be removed on each question and reused.

like image 221
kakubei Avatar asked Apr 03 '15 08:04

kakubei


1 Answers

Your problem is not in the code shown, it's in the code which returns the cell when requested, specifically because you aren't fully updating it by setting the status of both image views. So, when the cell is reused it has the wrong (old) settings from another row.

Really it's a data model and a cell design issue. The cell should always have 2 image views and you should just make visible or hide as required, and required should be determined from the data model which you update after each user selection and then reload (just update the cell when you can rather than fully reloading).

like image 188
Wain Avatar answered Nov 15 '22 03:11

Wain