How To Create a Rotating Wheel Control with UIKit

This is a post whew you will learn how to build custom Rotating Wheel Control with UIKit, written by iOS Tutorial Team member Cesare Rocchi, a UX designer and developer specializing in web and mobile applications. There may be times you’ve downloaded a cool application with a new kind of user interface component, and you’ve […] By Cesare Rocchi.

Leave a rating/review
Save for later
Share

This is a post whew you will learn how to build custom Rotating Wheel Control with UIKit, written by iOS Tutorial Team member Cesare Rocchi, a UX designer and developer specializing in web and mobile applications.

Learn how to create this cool rotary wheel control!

Learn how to create this cool rotary wheel control!

There may be times you’ve downloaded a cool application with a new kind of user interface component, and you’ve wondered: how was it built?

One great example of this is the rotary wheel, used by ConvertBot and other applications as a way for users to select options from a menu.

This component is intuitive to use because it resembles many similar controls we use in real life to make choices. For example:

  • A ship’s wheel allows the captain to choose the direction of travel.
  • To set the volume of your stereo, you use a rotary knob.
  • You might also remember that we used to call people using rotary dial telephones.

Such shared knowledge allows us to recognize the “possible uses” of a rotary wheel, even when it’s a virtual wheel.

Note: A perceived use of an object is also called an affordance, a concept used in such fields as psychology, design, and artificial intelligence.

In brief, a rotary wheel is meant to be spun. Just as with hardware wheels, touchscreen wheels can be configured in many ways. For example, we might include stop points (as in the rotary dial on a phone), ignore initial taps in a given zone, allow just one direction of rotation, etc.

As you may have deduced, this tutorial will show you how to build an intuitive rotating wheel interface. You’ll then be able to integrate this component into your iOS apps and let other people wonder how you built it ;]

Getting Started

The rotary wheel you’re going to build will be split into selectable sectors, where each sector represents an item on a menu. Each sector will be an image of a shape, and an arrow will indicate the currently selected sector.

By the end of this tutorial, your wheel will look something like this:

Here’s how it will work from the user’s point of view:

The wheel will not have a stop point, so it can be spun in either direction for as long as you want. When the user raises their finger from the touchscreen, the component will detect the sector currently closest to the “beak” on the left side of the outer circle, and adjust the wheel so the sector is centered on the beak. The selected sector will have a slightly darker background.

Although this wheel looks easy to use and there aren’t too many lines of code involved, there is a lot at stake in this tutorial. You’ll need to be acquainted with:

  • Building a custom component.
  • Detecting taps and calculating tap points.
  • The basics of trigonometry.
  • Transforming a drag gesture into a rotation.
  • Using affine transformations in QuartzCore.

This tutorial will touch on all of these topics on the way to constructing a rotating wheel control.

Creating the Control Class

The first step is creating a project and the basic class for your component.

For the purposes of this project, a Single View application is more than enough. Start up Xcode and create a new project with the iOS\Application\Single View Application template.

In the next step of the wizard, do the following:

  1. Give the project the name “RotaryWheelProject”
  2. Set the class prefix to “SM”
  3. Select iPhone as the device family (but the component will work on the iPad as well)
  4. Disable storyboards
  5. Leave Automatic Reference Counting enabled

You should end up with a bare bones project, which includes a delegate and an empty view controller as in the following picture:

Now you’re at a crossroads. To create your new component, you can extend either of two classes: UIView or UIControl.

UIControl inherits from UIView, and from an object-oriented perspective, it is better to extend the most specific class. The only difference is in the methods you have to override to obtain the intended behavior. In this tutorial, you will extend UIControl, but I will provide additional instructions in case you choose to extend UIView.

Now that this decision has been made, create a new file with the iOS\Cocoa Touch\Objective-C class template. Name the class SMRotaryWheel, and make it a subclass of UIControl.

Before we edit the SMRotaryWheel class, we are going to add another new file first. This new file defines a protocol to be used by the SMRotaryWheel Class.

Once again create a new file, but this time with the iOS\Cocoa Touch\Objective-C protocol template. Name the protocol SMRotaryProtocol.

The protocol definition is fairly simple – replace the contents of SMRotaryProtocol.h with the following:

#import <Foundation/Foundation.h>

@protocol SMRotaryProtocol <NSObject>

- (void) wheelDidChangeValue:(NSString *)newValue;

@end

That is the method that will be called called whenever the user lifts their finger from the screen. It indicates a new selection has been made from the menu. You’ll see how to use it in a bit.

Now switch to SMRotaryWheel.h and import the protocol below the existing import statement.

#import "SMRotaryProtocol.h" 

Then, add the following properties above the @end line:

@property (weak) id <SMRotaryProtocol> delegate;
@property (nonatomic, strong) UIView *container;
@property int numberOfSections;

These properties keep track of the delegate to notify when the user selects a section, the container view that the rotary wheel will be inside, and the number of sections in the rotary view.

Below properties, add the following method:

- (id) initWithFrame:(CGRect)frame andDelegate:(id)del withSections:(int)sectionsNumber;

The above method will be called from the view controller to initialize the component.

Now switch to SMRotaryWheel.m and replace its contents with the following:

#import "SMRotaryWheel.h"

@interface SMRotaryWheel()
- (void)drawWheel;
@end

@implementation SMRotaryWheel

@synthesize delegate, container, numberOfSections;

- (id) initWithFrame:(CGRect)frame andDelegate:(id)del withSections:(int)sectionsNumber {
    // 1 - Call super init
    if ((self = [super initWithFrame:frame])) { 
        // 2 - Set properties
        self.numberOfSections = sectionsNumber;
        self.delegate = del;
        // 3 - Draw wheel
        [self drawWheel];
	}
    return self;
}

- (void) drawWheel {
    
}

@end

Here you’ve added a private method called drawWheel, synthesized the three properties and defined initWithFrame:andDelegate:withSections: where the parameters are saved in the properties and the drawWheel method is called to draw the wheel.

Note you haven’t implemented the functionality for drawing the wheel yet, but you’ll get to that soon :]

For now, it’s time to compile and run! Unfortunately you’ll just get a blank screen at this point, but it’s good to verify the absence of compilation errors at every stage of your coding.

Contributors

Over 300 content creators. Join our team.