Product · August 29, 2022

Open-sourcing our photo layout for SwiftUI

LazyCollectionView – A modest attempt to port UICollectionView to SwiftUI.

Olivier Collet
Olivier Collet

The backstory

At Unsplash, we started using SwiftUI in our iOS app in 2020. Initially, we decided to build new views with SwiftUI, and whenever we redesigned a relatively simple view, we converted it from UIKit. This year, however, we stepped it up and began to convert more complex views.

One of the biggest challenges was converting our photo list view, showing photos in columns. We were using a UICollectionView with a custom layout, and unfortunately, SwiftUI doesn't offer any equivalent that can lazy-load views.

LazyCollectionView is a modest attempt to solve this. Although we wrote it mainly to handle our specific use case in the Unsplash app, we tried to make it “open” enough so it could allow for any type of custom layout.

At WWDC 2022, Apple released the SwiftUI Layout API, which does not lazy-load its views; therefore, it is not recommended to display a large number of items. So we decided to release this component on GitHub.

How it works

There are three components.

LazyCollectionView

This is the view you use in your code. You embed it in a ScrollView, which is convenient because you can mix it with other views, like a header and footer. You need to pass it the frame of its parent view so it can figure out which views should be displayed for the current scroll position. The views are laid out in a ZStack that updates whenever the scroll offset changes.

LazyCollectionLayoutAttributes

It holds the position where single views are displayed in LazyCollectionView.

LazyCollectionLayout

This is where you configure where views are positioned. You need to create a class that adopts this protocol.

Usage

Here is the typical way to use LazyCollectionView.

GeometryReader { geometryProxy in
    let parentFrame = geometryProxy.frame(in: .local)
	
    ScrollView {
        LazyCollectionView(data: myArray,
                           layout: myCustomLayout,
                           parentFrame: parentFrame) { item in
            ItemView(item)
        }
    }
}

Final words

We're excited to share this component because we hope it can be helpful to our fellow SwiftUI developers. Surely, it can be improved, so contributions are more than welcome!

Will someone attempt to write a CoverFlow layout?

You can find the project on Github at https://github.com/unsplash/swiftui-lazycollectionview.

Share article