Replicating Apple Music card deck transition
iOS 11 Music app features a lovely sliding cards UI for stuff that modally pop over the existing content. Here's how to replicate it in your app.
This is wonderful piece of UI, one of the nicest additions to Apple’s iOS 11 apps. I was really hoping that UIKit team would bring this as another UIModalPresentationStyle option1 in iOS 12 but alas, did not happen.
So…can we replicate it?
I found this extensive library by Harshil Shah which is close to 2k stars on GitHub. There’s also tutorial on Ray Wenderlich site by Warren Burton, made for custom use case (it’s built as re-usable library). I tried both and they both lacked certain details that make the transition totally joyful.
With that said, let’s analyze the transition.
- It uses spring-based animation with very little overshooting, meaning that presented card does not bounce much back and forth at the end, it just sort-of slides to ending position.
- The background view slides down, precisely synced with the card appearance.
- The background view slides up, precisely in sync with the card disappearing.
- The background view is dimmed to dark but nor blurred.
- Status bar appearance is always changed to
lightContent
when card is presented. This happens as soon as present transition starts. - Transition is fully interactive when presenting.
- It’s not interactive when dismissing.
- Can be dismissed by sliding the presented content down but only if the scrollable content is at the top.
- It shows downward-facing glyph at the top of the card which interactively changes shape during transition.
- Presented content’s layout is animated along the transition, with full interactivity preserved.
- When presented scrollable content is not at the top, tapping on the status bar scrolls the content to the top, as expected.
- If presented scrollable content is at the top, tapping the status bar dismisses the card.
- The bottom corners of the card are not rounded
- The top corner radius of the card is interactively increased during the transition
- Apple Music is fixed to portrait-up orientation (even on iPhone Plus models) thus is not clear if anything would need to behave differently in landscape.
Wow. That’s a lot of details to take care of but this is what it takes to create UI as joyful to use as this one is.
Guidelines for UIKit controls
When I try to do add some new control to UIKit, I stick to these guidelines:
- lean on existing APIs, don’t replace them
- make the feature as trivial as possible at the point of usage
- move the cost and complexity into internal behavior
- don’t try to handle all possible cases
There’s already so much new stuff to learn every year, thus I’m not a fan of re-learning what I already know. This is the main reason why I avoid libraries which entirely replace existing platform technologies like Auto Layout, Table and Collection Views etc.
Similarly, handling everything you can think of in a control like this often leads to complexity for everyone for the benefit of the few. Thus I don’t offer that many options to choose from; in fact, there are no options at all in my solution:
CardPresentationController
I built a micro library called CardPresentationController, available on GitHub under MIT license.
I think it works rather well; it has a total of 4 short files and it’s built using the same APIs UIKit is using for a feature like this: UIPresentationController
and friends. I’m also using UIViewPropertyAnimator
API which is really fun to play with.2
The main trouble with UIKit APIs here is that UIViewTransitioningDelegate
is, per Apple, implied to be the same UIViewController
object that presents the modal. This is consequence of the fact that UIKit really does not have any specialized concrete objects apart from UIViewControllers.
I don’t like to pollute my UIViewController code with unrelated things like this. Thus I opted to create a custom object called CardTransitionManager
which is strongly referenced by presenting UIVC. However, its creation and lifecycle management is compartmentalized into the library and works like magic one-liner.
Hence after adding mentioned 4 files into your project, you only need to replace your
present(vc, animated: true)
calls with
presentCard(vc, animated: true)
and you get the new UI.
The only big feature I’m really missing is interactive presentation and dismissal. I opted to create a solid base that works as easy replacement for existing full screen modal presentations and add nice-to-have stuff later on.