DEV Community

Chris Harding
Chris Harding

Posted on • Originally published at chrisharding.io

Building a calendar in Swift

In this post, I wanted to walk through an approach I used when building a calendar view in Swift for an iOS app I’m working on. The requirements were as follows:

  • Should start from the current day, and then scroll backwards through time
  • Each month is it’s own section, with corresponding header
  • Days should be a selectable square cell, and we should have 3 days on each row
  • The grid should take up as much screen real estate as possible
  • It should be memory efficient

And with any luck, it will look something like this...

a calendar view layout

With this in mind, I decided to use a customised UICollectionView, as most of the work around grid layouts and memory optimisation are done for me.

Bring the calendar to life

The first step in this process is to initialise a collection view. That’s relatively simple as follows

Most of this code is layout plumbing such as setting the frame size to it’s container, along with constraints to anchor it's size. This will fulfil my requirement around maximising screen real estate.

Go with the flow (layout)

Next up, I wanted to further optimise the layout such that the day cells are as big as possible. To achieve this, we can subclass UICollectionViewFlowLayout. The important methods to implement are as follows

Here we are calculating the maximum size of cell, based on the current frame and padding used. This should yield 3 day cells on each row, each maximising the width.

This subclass now needs be registered with my collection view as follows

Make it fancy

The final piece of layout required are definitions for what the day cells and month section headers will look like. To achieve this, I created two simple nibs. The day cells need to subclass UICollectionViewCell as follows

Nothing out of the ordinary here, just a label being set. I did however implement static convenience functions so that details such as reuse identifiers are encapsulated. As for the month header, we need to subclass from UICollectionReusableView

Note how we register this as a kind of UICollectionView.elementKindSectionHeader. We now need to tell our collection view to use these templates when creating new header and collection cells.

Let there be data

Finally, we need to tell the collection what it’s actually supposed to be rendering. I achieved this by firstly implementing a manager class which will calculate the necessary data, and put it into an efficient struct format.

The reason for this is that we can calculate this once, upfront, and then simply lookup the relevant data at render time (as opposed to re-calculating for each cell). Here is the supporting code to decide how many months we need to show, along with how many days each month contains

With this data in place, we again lean on the on the built in collection view functionality and subclass UICollectionViewDataSource

As you can see, returning the relevant section and cell data is just a lookup from our array. We can now hook this data source up to the collection view and away we go!

Looking back through the approach I have taken, I'm pleased to say it meets all of the requirements I set out at the top. This makes me happy.

You can see the full Swift calendar source code for this solution here: https://github.com/wdchris/calendar-grid-swift

Top comments (1)

Collapse
 
hlc0000 profile image
hlc0000

Hello, I developed a lightweight general cache library with swift 5. If you happen to use swift to develop IOS projects, if you need to use the cache library, maybe you can try swiftlycache, which I developed, and maybe you will like it
github.com/hlc0000/SwiftlyCache