Core Graphics: custom drawing with iOS SDK – Part 5
Thank you very much for the long list of questions and emails about this post series and sorry for the long waiting time for this new episode, but during the last months we got very busy with a couple of large iPad and iPhone projects. This time, I want to cover a very nice topic: color gradients. I think it is a very important topic, because combining gradients can provide your drawing with a very nice look.
Color Gradients
A color gradient is a smooth transition from any color to a different one. This transition makes your drawings more realistic and look gorgeous. There are essentially 2 ways to draw a gradient in Core Graphics, You can either use a CGGradientRef object or a CGShadingRef object. The first approach is very simple and allows you to draw linear gradients. The second approach is a bit more complex, since the user has to specify a CGFunctionRef object to draw a gradient with any shape. So, to draw a color gradient with CG, you need to:
- Define a color space
- Define the list of colors you want to draw
- Define the locations where you want the colors appear
- Draw (finally) your gradient; and, finally
- Free up your memory
Color space
So, first let’s give a look at the color spaces. A color space specifies how color values are interpreted by the graphic engine. A color space is usually a multi-dimensional space, each dimension of which represents a specific color component. Defining a color space in Core Graphics is quite straightforward. Give a look at the class CGColorSpace. I usually use the CGColorSpaceCreateDeviceRGB function, but you can use any of the other functions provided in the class.
Memory management
Just a small interruption here, since I missed an important point until now. The memory management in Core Graphics follows the simple rules of the retain count mechanism. You would ask me: “Ehy, wait a minute didn’t you say CG is C-based? So, no objects?”. You are right. And indeed, we are not using objects. However, it is common to call objects the CG references. These are the variables of a type ending with Ref. For example, when you create a color space, you create a reference (a pointer) of type CGColorSpaceRef. This is simply a pointer, but we usually call it an object. Now, whenever you create a CG object (or in general, a Core Foundation object) with a function whose name contains the word Create or Copy, you are responsible of releasing that object. In general, you can use the Core Foundation function, CFRelease. However, in the case of the color space, there is a specialized function for that: CGColorSpaceRelease. So, if you create a color space with the above mentioned functions, you need to release it as show in this chunk of code:
CGColorSpaceRef colorSpace =
CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
// other code here
CGColorSpaceRelease(colorSpace);
Gradient example
So, let’s see how we can create a linear gradient, first. Let’s color the whole screen. So, open Xcode, create a new View-based project, create a new class subclassing UIView and add a view to the main view of your custom view controller. In the MyView class, edit the drawRect: method as follows:
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat components [12] = {1.0, 0.0, 0.0, 1.0,
0.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0};
CGFloat locations[3] = {0.0, 0.5, 1};
CGGradientRef gradient =
CGGradientCreateWithColorComponents(colorSpace,
components,
locations,
(size_t)3);
CGContextDrawLinearGradient(ctx,
gradient,
CGPointMake(320, 0),
CGPointMake(0, 460),
(CGGradientDrawingOptions)NULL);
CGColorSpaceRelease(colorSpace);
}
So, what is this chunk of code? First, we get the reference of the current graphic context. We need that to draw the gradient. Then, we create a reference to the color space. I decided to use the RGB color space. This multi-dimentional space has 4 components: Red, Green, Blue and Alpha (the transparency). Each component can have a value between 0 and 1. After creating the color space, we create the color components. This is a vector containing the 2 or more colors you want to use in your gradient. In the above example, I used just 3 colors: one with Red = 1, Green = 0, Blue = 0 and Alpha = 1. The second component has the Red = 0, Green = 0, Blue = 0 and Alpha = 1. And the third component has the Red = 0, Green = 1, Blue = 0 and Alpha = 1. Now, we have to tell CG where to draw these colors. Here, there is a little bit confusion. To draw the linear gradient, we use the CGContextDrawLinearGradient function. This function asks to specify the 2 points in the view where to the gradient starts and ends. You can see I created 2 CGPoints. Now, imagine to connect these 2 points with a segment joining the points. The aim of the locations vector is to define the percentage of that segment where the components are placed along it. In the above example, the first color is at the 0% of the segment (i.e., the beginning), the second component is at the 50% (just in the middle) and the last color component is just at the end. If you now run your project, you should get this:
Very cool, eh? Now, imagine to combine this with shadow and transparencies . You can make really cool stuffs. Try to play a little bit with this and apply it to the paths. Our approach is to combine the graphics prepared by our graphic designer and the real time drawing of Core Graphics. You can make really beautiful pieces of arts. Next time, hopefully soon, we give a look at Core Text, another powerful core technology used to render text in real-time. Geppy Simplify, simplify, simplify
