Clear, a todo-list app by Realmac Software recently took the tech and design community by storm with its sexy new take on no-button, gestural interfaces. For those who haven’t seen it, it’s worth watching their intro video. It exudes class. We tip our collective Massive Health hats to Clear’s great work.
In addition to the novelty of the gestural interface, Clear had an exceptional new visual metaphor for manipulating and adding todo items: simple paper-like folds. Being a fan of wonderful products that surprise and delight, we spent a day recreating some of Clear’s primary user interactions and wanted to share what we learned (and our code) with the wider community.
Please don’t take the code and just recreate Clear—that’s not nice—but do use the techniques as a source of inspiration for your next project.
We implemented a number of the interactions: pull to create, pinch-open to unfold a new todo, pinch-close to fold away a todo, and of course a way to do it all programmatically. For the impatient, you can get the repo here. Here it is in action:
How Did You Do That?
To recreate Clear’s effects, all it takes is some Core Animation layers, trigonometry, gesture recognition, and more trigonometry. Sitting comfortably? Here we go.
Clear has four different cell states which we’ve named fold back, pinch, fold up, and flat:
All four of these states don’t need to be special cased in our code, although it may appear that way at first glace. If we lay the problem out correctly they can all be represented with the same five lines of code. We start by splitting the layer into two parts and defining two anchor points: at the bottom of the top half, and the top of the bottom half. Here’s the code (we’re taking advantage of Core Animation’s 3D transforms):
What’s going on? Each state can be constructed by translating the top or bottom layer by its anchor point by
[z=h*sin(θ)] and rotating by angle
[θ=cos-1(y/h)] where y = ½ the current cell height and h = ½ the original cell height.
In order to make the 3D projections line up properly and dramatically simplify the math, we change the anchor points of the layers to align with the center of our parent folding layer. For those of you following along at home, that’s (0.5, 1) for the top layer and (0.5,0) for the bottom layer. If we don’t transform anything we already have the flat layer.
One down, three to go.
As we shrink the height of our layer, we need to rotate the layers forward by the appropriate θ so their edges touch the front plane. You might be tempted to just skip the 3D and use 2D transforms to fake the effect. Trust us, that approach will end in tears. To get the pinch effect we rotate the top and bottom layers by the appropriate θ and -θ so the layer halves stay the same height. This puts the layers in front of the screen so we need to translate the layers back by z. That’s 2 down. If we want to fold instead of pinch, translate the layers back by z and rotate both layers by θ or -θ and they will line up. As you can see above, that’s just one
CATransform3DMakeTranslation and one
CATransform3DRotate per layer half and we’re done.
What about pinching and stuff?
The use of contextually appropriate gestures are what make Clear really shine. For gesture management in iOS5 we can use
UIPanGestureRecognizer. This example uses a full screen
UIScrollView for bouncing and scrolling large lists and adds a bunch of our folding layers directly to the scrollview’s layer. The approach is to create a new layer when a gesture begins, adjust the size of your layer when the gesture changes, and finalize/delete the layer when the gesture has ended. At the end of each gesture change state we relayout our layer frames. Thanks to Core Animation our layers will animate between states for you automatically.
Want more specifics? The nitty-gritty is all in the code.
Give me the code!
Want to do something like this in your project? Want to contribute? The source is hosted over here on github. We call it Opaque. Feel free to fork it and make it your own. Just submit a pull request if you’ve got something cool.
Read the source for a full understanding of how it works—this blog post talks about the most important parts, but clearly doesn’t cover everything. The code is also just a prototype. If this were a production app, some obvious improvements would be:
- Layers should track finger locations when pinching to create layers rather than using the pinch scale.
UIViewsbacked by custom
CALayersinstead of using raw layers in our view hierarchy.
- Support arbitrary view hierarchies and avoid the two-text-field trick we used by rendering the cell contents into an image and using that as the layer contents while animating.
- Create a
MHFoldingTableViewwith a datasource and delegate and move our layer/cell layout into that view instead of the gesture recognizer.
Interested in building awesome software to save lives and change the world for the better? So are we, and we’re hiring! Head over to our Jobs page and send us your resume.
Please send thoughts, feedback, improvements, ideas, haikus, hatemail, and suggestions to firstname.lastname@example.org and you can find me on Twitter at @yipe. Massive Health is not affiliated in any way with Realmac Software. We hope you take some of these ideas and build innovative new products with it!
A bit about the author: Michael recently ran a leading mobile agency producing award-winning iOS apps and mobile strategy for Fortune 500 brands. He also built AppleTV’s cinematic user experience, shipped beautiful apps for Apple’s Mac OS team for 6 years, and traveled Southeast Asia for a year with two cameras and a large unkempt beard. He’s excited to be back building products that matter.
Oops we accidentally posted this on Aza’s Tumblr account - this post was written by our awesome engineer, Michael Margolis (@yipe) though.