When was the last time you used an app that felt surreal, or broke the laws of physics? With modern apps becoming flat and simple, apps that felt magical are becoming exceedingly rare! In this talk from try! Swift, Adam Bell dives deep into how to prototype and build great interactive gestures and animations with Swift, so we can restore that sense of magic that’s been lost with time.
Introduction (0:00)
My name is Adam Bell, I’m a Canadian iOS engineer, and I’m currently at Facebook on iOS app experiences. I’ve been with the iOS community ever since the dawn of the iPhone. Over the years, I’ve released MessageBox, which was a hack for the Facebook app to allow chat heads to work everywhere, and Stride, which was a way to unlock your phone with gestures instead of passwords.
The Early Days (2:27)
When the iPad first launched, there were two things I remember getting extremely excited about: the iPad itself, and the animations and interactions.
Remember for example, the motion of how the iBooks app looked, things flew forward, you can turn the pages, and you’d see a page curl effect. In the Photos app, you could pinch into albums, and you were literally peeking into a collection of stacked images. You end up manipulating these digital representations of real world photograph albums.
In Mail, through the animations/interactions, you were given a discrete context of what’s happening with stacks of multiple emails. These interactions are something special.
The Early Days (4:07)
iOS 7 focused on consistency. Every part of the system should act in the exact same way, but this also meant they stripped away a lot of the things that made it great. They replaced a lot of the old interactions with new ones that were less animated, more robotic in nature. They were less gestural, and there’s much less delight and magic in apps anymore.
An example is Passbook. When deleting a pass, it used to show it being shredded - and it was immediately obvious what was happening. You’re not getting that pass back, it’s gone. In iOS 7, there’s no magic anymore, the pass just disappears.
Remember the Twitter app for iPad, you’d have your stream and panes. You could tap on things and have an accordion of things that would swipe in. It was immediately obvious what was happening. You had a navigational context you understood. Two months ago, they’ve flattened it into an iPhone app that just stretched out - it feels like Android.
Skeuomorphism (6:55)
There’s an extremely huge gap between skeuomorphism and interaction, and animation for that matter.
Skeuomorphism is the act of making something digital represent its real world counterpart. However, interaction is the fashion with which one thing interacts with another thing. Therefore, skeuomorphism is not actually interaction. They’re very two discrete things. Skeuomorphism, for example, is making your app look like a scrapbook by making the photos look like they were cut out of a book and interacting with them. Interactions are the ability to make your apps playful. They’re how you make your apps playful, how you guide a user through your app.
Reasons for Animations (8:01)
Animation is a critical element of interaction. It’s what fills in the gaps between the periods of time before, during, and after an interaction. It brings closure to what’s happening. If you’re opening a document or form of media, it should zoom into view to say where it’s coming from. If you’re closing a document, it should return to where it was.
Not only are these visual cues easier on the eyes, but whoever’s using your app immediately understands what’s happening. It creates a hierarchy of navigational construct. Do perform animations with a specific intent, to draw someone’s attention to what’s going on, or to indicate things that are going to happen. Don’t add animations for the sake of adding animations.
On Animations Being Slow (12:10)
What makes them slow? Does it physically drop frames, does it make your phone slow down?
Core Animation
Core Animation is actually specifically designed to make sure that animations don’t drop frames. Since all of these animations are performed at a process, they talk with a thing called a “CA render server”, which is actually given a higher priority than your application. This guarantees that everything is going to be nice and snappy. So unless you’re doing some crazy unoptimized drawing calls, it usually shouldn’t slow things down.
So now that we’ve established that Core Animation in iOS itself isn’t technically slow, there’s a different part of slow, where animations themselves can actually physically run for too long, and this is where they’re actually more painful than than the laggy ones. If someone has to fight your app, they are going to delete it.
On Animations Being Hard to Build (15:23)
Animations being hard to build is usually the most known issue with implementing them. However, they can be extremely rewarding to build. Good animations and dynamic interactions are what make your app really stand out. Challenge yourself to build something great. As an engineer, you’re pretty smart.
Challenge yourself to build something great. As an engineer, you’re pretty smart.
Difficulty should never be the reason to compensate for something, or settle on a lesser good idea. Figure out a solution that makes it plausible, then iterate on it. Iteration is always better than deletion.
Prototyping Tools (16:53)
The tools you already know:
- Origami
- Quartz Composer
- Form
- Framer
Xcode used to be terrible for prototyping, because it required building and running with each iteration, but with Swift and Playgrounds, prototyping is awesome. Xcode Playgrounds compile and run your app in real time, and any modifications will be updated dynamically, so it’s excellent for iterating.
The tool supports touches, such as tap gesture recognizer and pan gesture recognizer. They’re great for working with, but they take a lot of time to set up.
let tapGestureRecognizer = UITapGestureRecognizer(self, selector:Selector("doTheThing:"))
aView.addGestureRecognizer(tapGestureRecognizer)
@objc private func doTheThing(tapGestureRecognizer: UITapGestureRecognizer) {
switch(tapGestureRecognizer.state) {
case: UITapGestureRecognizerStateEnded:
print("ohai")
default:
break
}
}
We can do better:
let tapGestureRecognizer = UITapGestureRecognizer(view: aView)
.didEnd { (gestureRecognizer) in
print("ohai")
}
This is something I wrote out the other day. It’s called SwiftyGestureRecognition
, and I’ll open source it so you can try this out in your own Playgrounds.
SwiftyGestureRecognition
has similar syntactic sugar like Alamofire. You set up a request, and you get a response, and it’s block based and sequentially paired.
Prototyping Animations with Pop (21:35)
Pop is great for extending Core Animation. You can use Core Animation instead of Pop, but Pop works well on top with Core Animation. The problem of using Core Animation instead is that CALayer
is hard. CALayer
is actually powered by two internal layers.
CALayer
s can get out of sync.
The presentation layer, which is the state during an animation, and the model layer, which is the state after the animation completes. When you add an animation, you’re animating the presentation layer, and it’s going move something onscreen. When you remove all those animations, it’s going to jump back to whatever the model layer has.
When the animation ends, it should stop where it is. This is what CALayer
s should do, and that’s what Pop enables.
let layer = ...
guard let transform = (layer.presentationLayer() as? CALayer)?.transform else {
return
}
layer.removeAllAnimations()
layer.transform = transform
Here’s code where you remove the animation and keep everything in place. This is a lot of extra code you shouldn’t have to write. Pop lets you do this:
let layer = ...
layer.pop_removeAllAnimations()
You just grab your layer and you remove all animations. The difference here is it freezes it exactly where it is.
The nice thing about Pop is that all the animations run exactly in your app. Everything is done on the main thread, which means feedback is immediate, and it lets you do really cool things, like decay animations and springs.
A Real Demo (26:00)
We’re building a Pokédex.
I have this app, and it’s called Arcanine. We’re gonna make it a lot better, I’ve wrote a Core Graphics Poké Ball. This is a great example to show how physics can work in an iOS app when you’re prototyping. When I say physics, you might be thinking UIDynamics
. But the problem is, UIDynamics
requires you to set up many things like bounds, weight and mass, and skyboxes.
Here, we can fake it. We’re going to set up a UIPanGestureRecognizer
using the Swift code that I gave you. We attach the gesture recognizer to our Poké Ball, we have a didBegin
, so we have to remove all the animations that we’ll build later, and anytime we change or move our finger around, we’re gonna move the Poké Ball. So if we go and click on the Poké Ball, we can go and move it around, it’s gonna move around and interact live with us.
To Recap (37:14)
To recap, we used some fancy Swift’s syntactical sugar to make prototyping easy. We built some stuff that we can keep reusing. We build some pretty fun and fluid pop animations, and then used Xcode Playgrounds to iterate on our Pokédex app. Instilling magic into apps is something we should always strive towards, and continue pushing ourselves to do. The extra finesse that goes into making iOS apps great is now easier than ever with Swift and Xcode Playgrounds. When you really think about it, building an app should feel like you’re composing a symphony, but using it should feel as though you’re conducting an orchestra. Thank you.
Receive news and updates from Realm straight to your inbox