Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView cells stay highlighted after reloaddata

I have a UICollectionView with labels inside the cells that change automatically periodically. When this update triggers I call reloadData on the UICollectionView and I have set the cells to change the background colour on [UICollectionViewCell setHighlighted:].

The problem is if a user holds down on a cell then the update happens, when the user releases the cell stays highlighted and also cannot be selected anymore.

I have noticed that dequeueReusableCellWithReuseIdentifier:forIndexPath: calls setHighlighted on the cells after reloadData.

I have also tried reloadSections: instead of reloadData, this fixes the problem of the cells getting 'stuck', but causes a fade out and in on the cells when ever its called.

Placing the calls inside performBatchUpdates: doesn't seem to fix the problem either.

like image 873
richy Avatar asked May 24 '13 08:05

richy


3 Answers

Inside the cell's class try calling:

- (void)prepareForReuse {
    [super prepareForReuse];
    [self setHighlighted:NO];
    ... Any other custom stuff that should be cleaned up ...
}

The issue is that you are probably doing background coloring differently then the cell would normally do on its self when highlighted. Normally the cell's superclass would undo those changes in prepareForReuse, but it doesn't know about your changes.

like image 138
jamone Avatar answered Nov 11 '22 16:11

jamone


I used the following as a workaround:

// Both highlightedData and lastHighlightedData are only needed if you want to prevent user from selecting a cell which data changed during the reload. If not needed, a boolean may be used instead
@property (nonatomic) id highlightedData;
@property (nonatomic) id lastHighlightedData;
@property (nonatomic) BOOL pendingCollectionViewReload;

// Wrap the reloadData call. Enqueue it if there's a highlighted cell:
- (void)reloadCollectionView
{
    if (self.highlightedData) {
        self.pendingCollectionViewReload = YES;
        return;
    }

    [self.collectionView reloadData];
    self.pendingCollectionViewReload = NO;
}

// When a cell is highlighted, save its index, or better the related data:
- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    // Save data at indexPath to self.highlightedData
}    

// Then reload the data when the cell is unhighlighted:
- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    self.lastHighlightedData = self.highlightedData;
    self.highlightedData = nil;

    if (self.pendingCollectionViewReload) {
        [self reloadCollectionView];
    }
}

// The following can be used from shouldPerformSegueWithIdentifier or didSelectItemAtIndexPath to prevent actions if the data associated with the indexPath changed:
- (BOOL)selectedDataEquals:(id)data
{
    // I used lastHighlightedData in addition to highlightedData because this function may be used after the didUnhighlightItemAtIndexPath was called:
    return (self.highlightedData && self.highlightedData == data) || (!self.highlightedData && self.lastHighlightedData == data);
}
like image 32
silyevsk Avatar answered Nov 11 '22 16:11

silyevsk


I encountered the same problem in a collection view that didn't need highlighting and I noticed that the didHighlight/didUnhighlight methods behaved correctly, so I ended up blocking reloads while a touch was in progress, using something like this:

BOOL blockColviewUpdate,colviewUpdateQueued;

and then

-(void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    blockColviewUpdate=YES;
}

-(void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    blockColviewUpdate=NO;
    if(colviewUpdateQueued==YES) [self CollectionViewRefresh];
}

while using an own function instead of calling reloadData directly:

-(void)CollectionViewRefresh
{
    if(blockColviewUpdate==YES) colviewUpdateQueued=YES;
    else
    {
        colviewUpdateQueued=NO;
        [self.colview reloadData];
    }
}

It helped in my case and no reloads were lost.

like image 42
mpramat Avatar answered Nov 11 '22 15:11

mpramat