Continuous Rounded Corners with UIKit

Benoît Layer
Jan 10, 2019 · 3 min read

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:

Red has base corners, Orange has smoothed corners

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:

Sketch option to draw continuous (or 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 involvingUIView 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:

Toppler Settings screen

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.

Fueled Engineering

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store