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.
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.
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);
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With