At Fueled, we spent the last couple months building an awesome augmented reality game called Toppler to explore some of the capabilities of ARKit 2. We’ve already covered some of the technical lessons we leraned in two previous articles mostly related to SceneKit. Now it’s time to get back to UIKit and take a deeper look at some design concepts and their implementations for this more familiar framework.
We’ll be looking specifically at rounded corners. Not the ones you usually build with
layer.cornerRadius, but continuous rounded corners. Just so we’re clear on the difference, here is a comparison between classic rounded corners and continuous rounded corners that Apple introduced back in 2013, with the release of iOS7:
Notice the very thin red color that you can see behind the orange view. This is the actual difference between base and smooth corners.
For those of you using Sketch, the property to design continuous corners is called Smooth Corners:
Apple uses a private API to power its rounded corners in the SpringBoard. It’s
var continuousCorners: Bool from
CALayer. However, if you use this API in an app that you submit to the AppStore it will be rejected. 😕
There are a number of resources on the Internet to acheive the same effect in an approved way, usually involving
UIView subclasses and their own implementation of
drawRect. However, we’ve been preferring a much simpler solution, which you can apply to any
UIView with the help of a mask.
It turns out that
UIBezierPath(roundedRect:cornerRadius) produces a continuous corner. Simply using a
CAShapeLayer whose path is built with the previous function will also do the trick:
But stopping there would not be enough since our masked view will usually be resized during animations for instance, and the mask would not evolve in the meantime, unless we update it manually. To solve this issue, we can create a
UIView subclass to handle it for us.
To accomplish this, you can override the
bounds property to intercept any change, update our mask, and if needed, animate the change. The key to detecting an ongoing animation is to use the
animation(forKey:) function, which will return an optional running animation. We’ll copy this animation, to do our own updates, but use the same timing parameters:
Here’s a preview of what we achieved in Toppler by using these continuous corners alongside some animations and blur effects:
The augmented reality in Toppler represents the core experience. But we mustn’t forget the many other views that tie everything together to create a gorgeous and unique user experience. And that, my friends, always starts and ends with the ubiquitous UIKit.