Group Group Group Group Group Group Group Group Group Forums

Video Tutorial: Custom Collection View Layouts Part 10: Ultravisual – Cell Snapping

Learn how to implement a cool effect so that as the user scrolls the next cell snaps into place as it becomes the featured cell.

This is a companion discussion topic for the original entry at

Using UltraVisual demo on iOS9 for months and it runs fine, but running in Xcode 8 on iOS10 (Deployment Target still 8.2) and receiving error during scroll

2016-09-21 15:01:55.510438 Ultravisual[4159:1309927] *** Assertion failure in -[UICollectionViewData layoutAttributesForItemAtIndexPath:], /BuildRoot/Library/Caches/
2016-09-21 15:01:55.516660 Ultravisual[4159:1309927] *** Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘no UICollectionViewLayoutAttributes instance for -layoutAttributesForItemAtIndexPath: <NSIndexPath: 0xc000000001600016> {length = 2, path = 0 - 11}’

Identified the fix needed. Change UltraVisualLayout to inherit UICollectionViewFlowLayout instead of UICollectionViewLayout. After that works great in iOS10.

That almost fixes it… I had to play with the z index as well to prevent a semi strange flicker.

override func prepareLayout() {
cache.removeAll(keepCapacity: false)

let standardHeight = UltravisualLayoutConstants.Cell.standardHeight
let featuredHeight = UltravisualLayoutConstants.Cell.featuredHeight

var frame = CGRectZero
var y: CGFloat = 0

for item in 0..<numberOfItems {
  let indexPath = NSIndexPath(forItem: item, inSection: 0)
  let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
  /* Important because each cell has to slide over the top of the previous one */
  /* Initially set the height of the cell to the standard height */
    attributes.zIndex = numberOfItems - item

  var height = standardHeight
  if indexPath.item == featuredItemIndex {
    /* The featured cell */
    attributes.zIndex = 0

    let yOffset = standardHeight * nextItemPercentageOffset
    y = collectionView!.contentOffset.y - yOffset
    height = featuredHeight
  } else if indexPath.item == (featuredItemIndex + 1) && indexPath.item != numberOfItems {
    attributes.zIndex = item

    /* The cell directly below the featured cell, which grows as the user scrolls */
    let maxY = y + standardHeight
    height = standardHeight + max((featuredHeight - standardHeight) * nextItemPercentageOffset, 0)
    y = maxY - height
  frame = CGRect(x: 0, y: y, width: width, height: height)
  attributes.frame = frame
  y = CGRectGetMaxY(frame)


Actually, the only change you have to make is to implement layoutAttributesForItem(at:) which is required but was left out of the project. So, add:

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    return cache[indexPath.item]

That will clear the crash and should fix the flicker problems as well.

Anybody can some idea to how to do in Android ?

How could we do the cell resizing with images loaded from an url and not stored in de bundle?

How could we add the stretchy header from video 6 to this custom layout

I’ve successfully used Custom Collection View Layouts. I watched this series more as a refresher. There is perhaps one minor issue. If I run Instruments on my app it points to a memory leak in the vicinity of prepare(). I downloaded the finished app from lesson 10 and, sure enough, it shows a memory leak int the same area; in or around prepare(). I’ve spent an hour or so looking at the code and can’t spot any leaks.

It is easy to see: just profile the app with Leaks and you’ll see it shortly after the app launches.

Any ideas what could be causing it?

I love the topic of this course, but I feel like I only understand about 25% what’s covered. I wish there was more explanation, and or additional resources provided where I can learn about what’s happening and why, instead of just typing what the instructor types and hoping that it works…

1 Like