Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView top cell from zIndex not selected with overlapping cells

I have a UICollectionView with a number of cells that overlap each other.

I set their zIndex in a UICollectionViewLayout subclass with UICollectionViewLayoutAttributes so they appear in the desired order visually. The hit areas for touch evens work as expected with the cells with a higher zIndex coming though the collectionView:didSelectItemAtIndexPath: method when tapping the overlapping areas of the cell.

I transition to a UICollectionViewFlowLayout subclass and when I transition back to the first UICollectionViewLayout subclass the cells with a higher zIndex are not always selected when tapping the overlapping areas.

Further investigation revealed that the order of the UICollectionViewCells in the UICollectionView subviews is determining which cell is tapped.

I have written a method to reorder the subviews but this seems like a bit of a hack.

Is there a better way for the UICollectionView cells to return the expected index path in collectionView:didSelectItemAtIndexPath: based on how the cells appear visually?

like image 980
richy Avatar asked Nov 02 '22 03:11

richy


1 Answers

From my testing, it seems that layout-to-layout transitions ignore the zIndex property of the pushed view controller's layout. This smells like a bug. You can work around the issue by reloading after the view controller appears:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Reloading will clear selection, so we remember which index paths are selected before reload
    NSArray *selectedIndexPaths = self.collectionView.indexPathsForSelectedItems;
    NSIndexSet *allSections = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.collectionView.numberOfSections)];

    [self.collectionView performBatchUpdates:^{

        // First, reload to correct the zOrder
        [self.collectionView reloadSections:allSections];

        // Then, re-select the index paths
        if (selectedIndexPaths.count)
        {
            for (NSIndexPath *indexPath in selectedIndexPaths)
            {
                [self.collectionView selectItemAtIndexPath:indexPath
                                                  animated:YES
                                            scrollPosition:UICollectionViewScrollPositionNone];
            }
        }
    } completion:nil];
}

It's still a bit of a hack, but less messy than manually reordering the collection view's subviews.

like image 89
Austin Avatar answered Nov 12 '22 19:11

Austin