Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView setLayout:animated: not preserving zIndex

I've noticed that when calling setLayout:animated in a UICollectionView to switch between two layouts, the currently visible cell doesn't adhere to the zIndex it's layout attributes has been set in layoutAttributesForItemAtIndexPath:.

For example, if I were to have a UICollectionView with UICollectionViewFlowLayout, set it's minimumLineSpacing to a negative number so the cells overlap and then set a zIndex on each cell higher than that of the previous cell, then it appears as if the cells are stacked from the bottom up.

However this breaks if I set the layout to another layout then back to that original layout. It's as if the currently visible cell doesn't listen the zIndex and is placed atop the other cells. If I scroll the cell offscreen then back on it is in the correct place.

like image 678
sampage Avatar asked Sep 30 '12 06:09

sampage


5 Answers

I have had the same problem. Switching the layout will disregard the zIndex for the cell.

I have managed to make it "look right" by applying a translation on the z-axis like this:

attributes.transform3D = CATransform3DMakeTranslation(0, 0, indexPath.row);

But it is just a visual fix, if you try to click on the item you will realize that the zIndex is still wrong until it is recycled by scrolling it offscreen.

like image 52
TheoB Avatar answered Nov 15 '22 13:11

TheoB


I've managed to get the behaviour I'm after by using a combination grimfrog and Charlie Elliott's responses.

Charlie Elliott's solution got the correct final outcome for the items in the collection view but there was still a snapping effect on the zIndex during the animation.

grimfrog's solution provided the correct look but had the problem of the zIndex still being incorrect after the layout change, despite looking correct.

The combination of the two, while not a great solution, does work and does use the supported transform and zIndex properties of the UICollectionViewLayoutAttributes

In my layout, I have

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
  NSArray *attributes = [super layoutAttributesForElementsInRect:rect];

  [attributes enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *attributes, NSUInteger idx, BOOL *stop) {
    attributes.zIndex = attributes.indexPath.item + 1;
  }];

  return attributes;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
  UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath];

  attributes.transform3D = CATransform3DMakeTranslation(0, 0, attributes.indexPath.item);
  return attributes;
}

I won't make this as the correct answer just yet as I'm sure there must be another way to solve this, but I'm interested to see if this solves the problem for others as well.

like image 44
sampage Avatar answered Nov 15 '22 14:11

sampage


Try:

// In UICollectionViewCell subclass
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
{
    [super applyLayoutAttributes:layoutAttributes];
    // Setting zPosition instead of relaying on
    // UICollectionView zIndex management 'fixes' the issue
    self.layer.zPosition = layoutAttributes.zIndex;
}
like image 33
Nimer Avatar answered Nov 15 '22 13:11

Nimer


This bit me too. After several tests I realized that UICollectionView will force selected cells to be on top, regardless of the z-index.

like image 31
John Estropia Avatar answered Nov 15 '22 14:11

John Estropia


Try setting the z-index in:

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;
like image 39
Charlie Elliott Avatar answered Nov 15 '22 14:11

Charlie Elliott