Circular Layout and Scrolling – Part 2

I think for this post I’d like to continue implementing the rotary control I started in my previous post. In that example, all we really did was figure out how to arrange a series of numbers around a circle. I briefly mentioned how you could implement a rotation on the entire circle, but didn’t get into the details of how that works. So, for this post, we’ll add a bit of touch handling code to take care of rotating the entire circle based on the movement of a user’s finger on the screen.

Touch Rotation

Although the iOS multitouch system is very advanced, for this example, all we really need to is track a single finger as it rotates around the center of our circle. To do this we’ll implement the touchesBegan:withEvent and touchesMoved:withEvent methods of UIView, which are inherited from UIResponder. Since we’re now building this example out into a more full-fledged control, we’ll go ahead and create a subclass of UIImageView that will take care of displaying the same view as before, as well as handling touches to implement rotation. I’ve added the basic number layout to a “setup method” that’s called from both initWithFrame: and initWithCoder: (which is used when the view is loaded as part of a .xib file). One more method we’ll need is the one that actually calculates the angle of the rotation. What we need to know is the angle between the user’s finger and the center of our view. Now, I’ve learned some of this stuff before, but my trigonometry skills are, let’s just say a bit rusty, so when it came time to do these calculations, I was lost at first. However, Matthijs Hollemans has a nice open source rotary knob control that saved me a lot of time and headache of figuring this out. It turns out that math.h has a very helpful function called atan2(x, y). The introduction on the wikipedia article sums it up nicely: it returns the angle in radians between the positive x axis and the point given by the coordinates. What’s that mean for us? Calculate the x and y distance of a touch from the center of our view and pass that to atan2, which will return us the angle of the touch relative to our center. Once this calculation is figured out, basically all we need to do is store the angle of the initial touch in touchesBegan: and then each time touchesMoved: is called, calculate how much the angle has changed since the last call and pass this in as the rotation value on the CGAffineTransformRotate function to rotate the current transform by that angle. Here’s the source on paste bin. It’s the header and implementation in one paste. It’s just a UIImageViewSubclass, so drop it in IB or add programmatically like you would any other UIImageView to see what it looks like. Or skip the background image and just subclass UIView instead. Everything else will work exactly the same.

NB: In general, any custom touch handling object really should also implement touchesEnded: and touchesCanceled:, but in this particular case, it doesn’t really matter much to us when or how the touches stop. When our touches end (or get canceled), our touchesMoved: method stops getting called, and the UI is simply left at whatever rotation it last received. Once new touches start, we store that initial angle value and continue on from there.


There’s lots more I could show on this whole concept, especially about how to connect the rotation with a certain selection or value, and about how to display more content than what can fit around one circle, but I don’t want to go too much further right now for a few reasons: 1) My implementation works pretty well and is quite flexible, but the animations aren’t all quite right, and it’s still got a few nasty edge case bugs I’m trying to work out, so it’s not yet ready for mass consumption! 2) I’m not sure how much of this will be interesting to everybody. So, what I thought I’d do is share a little video showing at least the visual aspect of what my this thing can do, and if anyone is interested in seeing more code when it’s fully baked, then let me know what you’d like to see, and I’ll share what I’ve learned! Sorry for the bad audio; just using my earbuds microphone and trying to be quiet and not wake up my wife. Oh yeah, and the weird video aspect ratio. I wish the iPhone simulator wouldn’t act so jumpy when you rotate it. Anyway please let me know what you think and what/if you’d be interested in hearing more about with this control.

Using CGAffineTransform for Circular Layout and Scrolling


Hello, and thanks for stopping by my blog! This marks my first post as part of iDevBlogADay. If you’ve never heard of it, you should go and check it out. It’s basically a group of indie iOS developers who are committed to blogging on a regular basis about all the experiences of being an indie developer – everything from marketing tips, to code examples, to graphic design, to just about anything else you can think of. If you’ve found my blog through iDevBlogADay, then I just want to say a special thanks for stopping by to see one of the “new guys.” Hopefully you’ll find something here that’s helpful or encouraging, no matter what stage you’re in as an indie developer. Just a quick intro to me: I’m a relative newcomer to the developer scene and have been doing iOS development for just over two full years, with no other substantial programming experience prior to that. Currently I’ve got one app for sale on the app store (plus the Lite version) called theDrumDictionary. If you’re interested in that or more info about me and my background, you can find it on the previous posts in this blog. As of right now, this app and basically all my current ideas for future apps are focused on the area of tools for musicians. So if you have a particular interest in music or music apps, be sure to stop back by – or subscribe to the feed – and I’ll try to keep the blog posts coming with everything from specific music and audio programming things I’ve learned, to more widely applicable topics like interface design and code.

Circular Scrollers

For this post, I’d like to share a bit about the major interface control I’m working on for my upcoming metronome app. The basic idea is a rotary control that allows users to select between different values or options by scrolling around in a circle rather than simply scrolling up and down on a UITableView or UIPickerView.

The basic idea is inspired by the beautiful Convertbot by the Tapbots crew. The circular scroller idea itself goes back even further to the many generations of click wheel iPods prior to the rise of the iPhone and multitouch.

Convertbot Interface

It’s a fairly complicated mechanism, and there’s a lot that I could share about the implementation and why I chose this format, but I think I’ll save that for later posts. For now, how about a quick intro to the world of UIViews, CALayers and transforms that form the basis of my version of this control.

Circles are Freakin’ Hard!

If you’ve done any work on interface design on iOS then you’ve surely made use of the UIKit framework. For basic layout and presentation of views, UIView and its various iterations – UIImageView, UIScrollView, etc. – are pretty simple and straightforward. There’s a whole slew of properties you can access to set sizes and positions of views, as well as background color and alpha, and to top it all off, many properties are animatable. With very little code, you can get some pretty complicated looks and have all kinds of things flying in and out, zipping around, fading in and out, growing and shrinking, whatever you want to do. Combine this with the concept of adding views as subviews of others, and you can do all sorts of interesting layouts and animation with minimal effort. The first sort of problem we run into though is the fact that everything, and I mean everything, in the UIKit system is based around rectangles. CGRects to be exact. Every view has a square frame, is positioned within its superview in relation to the superview’s square shape, is defined in terms of rectangular sizes, etc. If you want to deal with circles – or any shape other than a rectangle for that matter – and handle touches, layout, etc. you’re going to have to take on some extra burden to get things looking and acting the way you want. Core Graphics, of course, offers methods for getting circles drawn onto the screen, or you can use pre made images with transparency, but either way, we’re still talking about a circle sitting inside a square UIView. 

The other major problem you’ll notice is that in all of the available properties for UIView, there is no “rotation.” Well, that’s a problem because this whole concept is based on nothing BUT rotation, and laying out views at various angles around a circle. For rotation, we have to turn to the UIView’s “transform” property. This property is of the type CGAffineTransform and allows us to take the underlying view hierarchy and model and transform it in various ways so that when it comes time to draw to the screen, the view has been altered. Views can be translated, scaled, and rotated. Even if you don’t understand the math behind matrix transforms – and I certainly don’t – you can still make good use of the CGAffineTransform using some Apple-provided functions. For rotation there’s CGAffineTransformRotate, which takes an existing transform as it’s first parameter and then rotates it by the angle (in radians, not degrees) given as the second parameter, adding to whatever translation, scale or rotation was already a part of the transform. Or, there’s CGAffineTransformMakeRotation, which will return a new transformation with only rotation at the given angle. Now that we’ve found the functions we need, for this post, we’ll just focus on getting a rudimentary number dial running. It’s not gonna be pretty, but it’ll get the job done. First thing to do is decide how many numbers we want to show and create the views to display them. I’m just going to use UILabels. So here’s what it looks like after the first step of just adding the main circle image to the view and adding 9 number labels as subviews of the circle in the center of the image. I gave the labels a background color to better see what going on, and an alpha of .2 so you can see that right now, it’s 9 labels all right on top of each other in the center. Now, to get them arranged around the circle, we’ll need to apply the rotation transform. Since we’ve got 9 labels, each label will be rotated 2π/9 radians more than the previous one to fill out the entire circle evenly. UIViews rotate around their centers, so in order to arrange the labels around the edge, we can make sure each label is the same width as the circle, then apply the rotation to get this:

Now, it looks OK, but you can easily tell that it’s not ideal. (Unless of course you’re making a kaleidoscope app!) All of these multiple overlapping views mean extra work for the rendering system, not to mention all the just plain waste of having each view extend all the way across the circle.

Cleaning It Up

How can we clean this up? The answer is to dive just a little bit deeper and access the “layer” property of the labels. Every UIView is backed by a CALayer that’s responsible for the actual drawing. UIView adds support for touch handling and presents a different set of API’s to interact with the drawing and animations, but behind every UIView, by default, is a CALayer. If you’ve got a developer login and can access the 2011 WWDC videos, I highly recommend the one called “Understanding UIKit Rendering.” It has a great chart that details some of the shared properties between UIView and CALayer and how they are accessed in each, as well as some of the differences. One property on CALayer that cannot be accessed from UIView is the anchorPoint. The anchorPoint is a CGPoint that defines the exact spot within the view’s own bounds that acts as its anchor to its superview. Confusing right? Maybe this will help: think of the layer as a sheet of paper that you’re pinning to a bulletin board. The anchorPoint is the spot on the piece of paper where the pin will be pushed through. The position property of CALayer is the spot where the pin will be stuck on the bulletin board. 

By default the anchorPoint is set to the center: (0.5, 0.5) – 50% of the way across in both the x and y directions. The exact relationship between UIView’s frame, bounds, center and CALayer’s  bounds, position, and anchorPoint can be difficult to understand at first, but the most important thing for us right now is to know that setting a CALayer’s anchorPoint means any rotation will be applied around that point, again, just like a piece of paper stuck to a cork board will rotate around the pin. So, first, let’s cut the width of our labels in half and position them at the left edge.  Then, we’ll set the anchorPoint to (1.0, 0.5) – the far right side and centered vertically. Now, when we apply the rotation transformation, the labels line up the exact same way as before, but without all the unnecessary size and extra overlapping.

Take out the red color, and we’ve got a decent start to a number dial. If we want to rotate the whole dial, apply a rotation transform on the whole circle image. Since the labels are subviews of the circle, they will rotate right along with it and also maintain their relative positions because of their own rotations. Aren’t transforms fun!!

Two things to note: 1) CALayer also has a transform property, but it’s separate and of a completely different type than the UIView’s transform property. BUT, since the UIView’s drawing is done in its CALayer, we can modify the layer’s anchorPoint property, and still see the results we’re looking for when we rotate the UIView’s transform. It’s all a bit confusing, but very powerful. 2) If you’re not already doing it, in order to access the CALayer API’s you’ll need to link against the QuartzCore framework and import that header in your file. Alright, I think that’s enough for now. Here’s the code on Pastebin for the final version if you’d like to check it out. Add it to viewDidLoad or similar, and don’t forget to clean up the memory (I was lazy for the example)! Happy transforming!

Head to Part 2, for adding rotation based on touch input.

Here’s a look at this concept “in action” as a tempo selector in my app.

The design is far from finished, but you can at least get an idea of what the control looks like. As this is my first iDevBlogADay attempt, I’d love to hear your feedback about the post: too long, too boring, too simple, did I get something wrong? Let me know what you’d like to read about! Thanks!