We recently developed a generic color picker that can be plugged in to any application.
More than once while designing our applications someone said the sentence, “Ok, now we need a color picker.”‘ More than once means we need a generic, reusable bit of code.
Decisions, decisions
The first thing we needed to decide was which method we wanted to use for selecting a color.
1. A predefined set of colors that the user selects from
Pros : This would be very easy to program. We’d show the user a predefined set of colors, and there are several ways we could do this programmaticly. Each color would be represented by a UIColor , and we would return that color whenever necessary.
Cons : Giving the user enough options while at the same time keeping a clean and good looking design proved problematic. Also, it seems less fun to limit the user to an arbitrary set of colors.
Decision : We dropped this option quite quickly since it was limited from the user’s point of view.
2.RGB sliders
Pros : Allows the user freedom in color selection. Very easy to code. All you need is a UIView to show the selection, and three UISliders - one for Red, one for Blue and one for Green. Then, you’d need to hook up a function to value changes in each slider that would create a color from the RGB value. To create a color from RGB values, use the
UIColor colorWithRed:(CGFloat)red green: (CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha
Cons : We felt that the mixing red, green and blue is very much a ‘computery’ concept. For people who don’t work with design or computers it feels akward and is very difficult to visualize.
Decision : While this is an option that we’ve seen in several places, we felt that it wasn’t a good fit for our applications, and would not be intuitive for the average user.
3. HSL (Hue Saturation Light)
Pros: Intuitive for users. Clear selection of colors from a palette.
Cons: More difficult to code than the RGB method.
Decision : After looking at regular desktop applications like Photoshop, We decided to use Hue, Saturation and brightness to select the colors. We felt that this would best communicate the color selection to the user.
After deciding on the method, we decided which parts of the selector would remain the same in every application , and which would be interchangable to fit the look and feel of each application.
We decided in the end that only the background mask would be something that can be changed.
These decisions were all made in cooperation with Rami, the designer.
Basically, we have something that looks like this :

Explanation: When using HSL for selecting colors, Hue and Saturation are selected with the middle matrix of color, and brightness is selected using the brightness bar below. The brightness bar shows a gradient of the color from white to black, where brightness moves from 0 to 255 - white to black.
Now, we’re ready to code it.
Programming The Color Picker
The Color Picker code will fit into the modal view controller pattern (as do all things cocoa touch). Basically what we’ll need is a view - henceforth the ColorPickerView, and a view controller - the ColorPickerViewController. The ColorPickerView will be formed by a nib file for the design, and a corresponding ColorPicker.h with the code.
When developing these apps, one of the questions you’ll often find yourself asking (or at least I did) is: Do I need the code file? Or is the nib enough? In this instance, I’ll be needing to recognize touches, so I definitely need the added code files. There are many other considerations for whether to make just a nib file, just a code file, or both, when making a new view for your app.
OK - So we have a ColorView.xib, ColorView.h, ColorView.m and ColorViewController.h, ColorViewController.m
This set will be easy to put into any project, but for development stage, I kept it in its own project, so I wouldn’t get stuck with other programs’ bugs.
ColorView.xib
This is where I set up the design - how things will look over all. The xib has in it :
- Current Color - This is a UIView* whose backround color will change according to the selection being made. Obviously, it must be an IBOutlet, so that this color can be changed programatically.
- Images - there are two images here - the crosshair for selecting a color within the matrix, and the bar for selecting the brightness. Both of these images will be animated and moving around the screen. Exciting ! These images can also be exchanged to fit the designs of different applications.
- Backround - A UIImageView * the size of the screen. This is set as an IBOutlet, so that it is generic and I can change it from program to program. The background image itself is a mask with clear holes for the color selection matrix, the color display, and the gradient view.
ColorView.h
This is where I’ll describe the programmatic additions that I made to the view.
- Color Matrix - I added the image of the ColorMatrix programatically. This is because I’m interested in being modular. The background mask that I put in the nib file can have any kind of sizes and frames, and the when setting up the picker, you set the value for the size of the color matrix image. For example, in one color picker, you might want to add the color in hex or RGB values. There’s not a lot of room on this screen for that, so an easy way to make room is to make the color matrix smaller. So by adding the color matrix programatically, I left the size of it modular. The size of the frame is something that we’ll use when implementing the touches.
- Gradient View - Like I stated earlier, when you change the hue and saturation using the color matrix, the brightness bar show a gradient of that hue and saturation ranging from brightness = 0 to brightness = 255. This gradient was acheived using built in Quartz methods. I’ll get to that in a minute
- Touches - All of the touch implementation is taken care of in the code for this view.
- Calculations - Calculations for all of the colors are also made from the code for this view. This might have been pushed out to the viewController for purist Modal View Controller, but I think we can forgive it staying here.
Gradient View
The gradient view is a separate class with a 2DQuartz implementation for gradient. When the hue/saturation values change, the gradient view is updated according to the new hue/saturation. To create a gradient, you need to decide on the source and dest colors - I chose White to Black. You can also select colors to go through. I chose the hue and saturation from the main view with the middle of the brightness scale. This gave me a pretty accurate gradient.
The Interesting parts of code
Setting up the gradient with the right colors
- (void) setupGradient {
const CGFloat *c = CGColorGetComponents(theColor); CGFloat colors[] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0,
//WHITE c[0],c[1],c[2],1.00,
//THE COLOR 0.0/255.0,0.0/255.0,0.0/255.0,1.0, //BLACK };
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4)); CGColorSpaceRelease(rgb);
}
Draw Rect
- (void)drawRect:(CGRect)rect { // Drawing code CGContextRef context = UIGraphicsGetCurrentContext();
// The clipping rects we plan to use, which also defines the locations of each gradient CGRect clips[] = { CGRectMake(0.0, 0.0, 300.0, 60.0), //self.frame, };
//The Gradient Will be drawn along a line parallel to the start -> end coordinates you give it. This way you can achieve any //linear gradient start = CGPointMake(0,0); end = CGPointMake(300,0); CGContextDrawLinearGradient(context, gradient, start, end, 0); CGContextRestoreGState(context); CGContextSaveGState(context); }And that’s it for the Gradient View!!
Touches
For the final trick, you want to give the user control over the crosshair and lightness bar. I did this referencing the ‘Touches’ Source code example from Apple.
Remember - we have two regions of interest -
- Is the user touching the color matrix ? If so - move the crosshair and change the hue + saturation, and gradient bar, and the window containing the current color.
- Is the user touching the brightness bar ? If so - move the selection bar, and change the brightness value, and the window containing the current color.
- Otherwise - do nothing.
So the user can touch anywhere on the screen, and we read all of it, but only react to certain areas.
There are three functions for touches - touchesBegan, touchesMoved, and touchesEnded. I used only began and moved.
// Handles the start of a touch
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
[self dispatchTouchEvent:[touch locationInView:self]];
}
// Handles the continuation of a touch.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
[self dispatchTouchEvent:[touch locationInView:self]];
}
-(void) dispatchTouchEvent:(CGPoint)position
{
if (CGRectContainsPoint(colorMatrixFrame,position))
{
[self animateView:crossHairs toPosition: position];
[self updateHueSatWithMovement:position];
}
else if (CGRectContainsPoint(gradientView.frame, position))
{
CGPoint newPos = CGPointMake(position.x,kBrightBarYCenter);
[self animateView:brightnessBar toPosition: newPos];
[self updateBrightnessWithMovement:position];
}
}The animate view method just takes care of changing the center of each of the images so that its in the new place.
That’s almost it ! There’s only one more thing
Calculations
1. Color Matrix - Hue and Saturation are values between 0 and 1. To calculate, we need to take use :
Hue = (position.x-kXAxisOffset)/kMatrixWidth; Saturation = 1.0 - (position.y-kYAxisOffset)/kMatrixHeight;
2. Brightness -
Brightness = 1.0-(position.x/gradientView.frame.size.width) + kBrightnessEpsilon;
And that’s it! You now have a color picker.
Congratulations
Questions and comments are very welcome! Thanks for reading.
Update with source code link
Thank you all for your patience. We have released hue under the BSD license. You can get the source from here.
- BROWSE / IN TIMELINE
- « Application design flickr set
- » Iphone UI and Usability Experience Series Introduction
COMMENTS / 13 COMMENTS
adrian added these pithy words on Apr 11 09 at 6:50 pmI noticed that the app is open source:
http://hue.v-vent.com/
Where can I download the code?Thanks,
Adrian
Benoit Cerrina added these pithy words on Apr 14 09 at 8:24 pmHello,
I would also be interested in downloading the code
Lia added these pithy words on Apr 17 09 at 3:27 pmhello,
first of all thanks for your tutorial!!!
i am very new to iphone programming and tried out the suggestions you made, but so far without success.
+ please please please: the source code would be great!![]()
Lia.-
ramijames added these pithy words on Apr 17 09 at 7:32 pmhi guys, this is rami. the source is on the way! don’t worry!
Jinu C Joseph added these pithy words on Apr 20 09 at 4:35 pmThanks for this concept. Please ..source code would be great!
Adam added these pithy words on Aug 01 09 at 11:45 amThanks for this tutorial and code! I want to change the color matrix size (to make more room) and I see you can do that by changing the constants in constants.h (kHueSatFrame, kMatrixWidth, kMatrixWidth), but I notice the “calibration” is off now, that is, the color selection doesn’t reflect the actual color. Should I adjust an other constants and if so how do you calculate their values? Thanks again for this info.
pegli added these pithy words on Sep 09 09 at 5:46 pmHey Rami, it would be great to have a LICENSE file in the source download so we can follow the BSD licensing terms properly. Thanks for a great contribution!
Coder68 added these pithy words on Oct 22 09 at 4:44 pmAt first sight one is puzzled, because the threshold to be overcome seems to be the same in both cases. ,
James added these pithy words on Nov 18 09 at 3:29 pmI would like to improve on this app an include it in a commercial product. I’ve read BSD license until I’m blue in the face… I can’t tell if using the app in a commercial product is allowable. Can anyone please help? Thanks so much.
Nathan added these pithy words on Dec 28 09 at 8:50 amHi, thanks for the great sample code. A few notes on the source:
- you need to release gradientView in - (void)dealloc of ColorPickerView
- kMatrixWidth, kMatrixHeight, kXAxisOffset, kYAxisOffset are all redundant definitions of numbers in kHueSatFrame
- you can do the drawRect for the GradientView in one line, and get rid of bad magic nubmers:
CGContextDrawLinearGradient(UIGraphicsGetCurrentContext(), gradient, rect.origin, CGPointMake(rect.size.width, rect.origin.y), 0);I’ll be posting my finish class later on. Thanks again!
Dan Selig added these pithy words on Apr 14 10 at 7:09 pmIs this free?
Do you ask for links from my support web site (I’d be very happy to do this)
Do you need your logo on the splash screen (as SIO2 does)?In any case: THANK YOU!
ramijames added these pithy words on Apr 14 10 at 9:33 pmWe don’t ask for any logos or links in return (but if you wanted to…)
the code is yours to use and abuse. Have at it!
J.R. added these pithy words on Aug 10 10 at 7:39 pmGreat code!! Thanks so much! One thing though… does anyone have an idea on how to initialize it with the last color that was chosen, rather than always starting at yellow… I tried a few things but it seems overly complex….
SPEAK / ADD YOUR COMMENT
Comments are moderated.

