The ability to draw two-dimensional graphics on the iPhone and iPad is provided as part of the Core Graphics Framework in the form of the Quartz 2D API. The iOS implementation of Quartz on iOS is the same as that provided with macOS. It provides a graphics context object together with a set of methods designed to enable the drawing of 2D graphics in the form of images, lines, fill patterns, and gradients.
In this chapter, we will provide an overview of Quartz 2D. A later chapter, entitled An iOS Graphics Tutorial using Core Graphics and Core Image, provides a step-by-step tutorial designed to teach the basics of two-dimensional drawing on iOS.
Introducing Core Graphics and Quartz 2D
Quartz 2D is a two-dimensional graphics drawing engine that makes up the bulk of the UIKit Core Graphics Framework. Quartz 2D drawing typically takes place on a UIView object (more precisely, a subclass thereof). Drawings are defined in terms of the paths a line must follow and rectangular areas into which shapes (rectangles, ellipses, etc.) must fit.
The draw Method
The first time a view is displayed, and each time part of that view needs to be redrawn due to another event, the draw method of the view is called. Therefore, drawing is achieved by subclassing the UIView class, implementing the draw method, and placing the Quartz 2D API calls within that method to draw the graphics.
When the draw method is not automatically called, a redraw may be forced via a call to the setNeedsDisplay or setNeedsDisplayInRect methods.
Points, Coordinates, and Pixels
The Quartz 2D API functions work based on points. These are essentially the x and y coordinates of a two-dimensional coordinate system on the device screen, with 0, 0 representing the top left-hand corner of the display. These coordinates are stored in the form of CGFloat variables.
An additional C structure named CGPoint contains both the x and y coordinates to specify a point on the display. Similarly, the CGSize structure stores two CGFloat values that designate an element’s width and height on the screen.
Further, the position and dimension of a rectangle can be defined using the CGRect structure, which contains a CGPoint (the location) and CGSize (the dimension) of a rectangular area.
Of key importance when working with points and dimensions is that these values do not correspond directly to screen pixels. In other words, there is no one-to-one correlation between pixels and points. Instead, based on a scale factor, the underlying framework decides where a point should appear and what size relative to the display’s resolution on which the drawing is taking place. This enables the same code to work on higher and lower resolution screens without the programmer having to worry about it.
For more precise drawing requirements, iOS version 4 and later allows the scale factor for the current screen to
be obtained from UIScreen, UIView, UIImage, and CALayer classes allowing the correlation between pixels and points to be calculated for greater drawing precision.
The Graphics Context
Almost without exception, all Quartz API method calls are made on the graphics context object. Each view has its own context, which is responsible for performing the requested drawing tasks and subsequently rendering those drawings onto the corresponding view. The graphics context can be obtained with a call to the UIGraphicsGetCurrentContext() function, which returns a result of type CGContextRef:
let context = UIGraphicsGetCurrentContext()
Working with Colors in Quartz 2D
The Core Graphics CGColorRef data type stores colors when drawing with Quartz. This data type holds information about the colorspace of the color (RGBA, CMYK, or grayscale) together with a set of component values that specify the color and the transparency of that color. For example, red with no transparency would be defined with the RGBA components 1.0, 0.0, 0.0, 1.0.
A colorspace can be created via a Quartz API function call. For example, to create an RGB colorspace:
let colorSpace = CGColorSpaceCreateDeviceRGB()
If the function fails to create a colorspace, it will return a nil value.
Grayscale and CMYK color spaces may similarly be created using the CGColorSpaceCreateDeviceGray() and CGColorSpaceCreateDeviceCMYK() functions, respectively.
Once the colorspace has been created, the next task is to define the components. The following declaration defines a set of RGBA components for a semi-transparent blue color:
let components: [CGFloat] = [0.0, 0.0, 1.0, 0.5]
With both the colorspace and the components defined, the CGColorRef structure can be created:
let color = CGColor(colorSpace: colorSpace, components: components)
The color may then be used to draw using the graphics context drawing API methods.
Another useful method for creating colors involves the UIKit UIColor class. While this class cannot be used directly within Quartz API calls since it is a Swift class, it is possible to extract a color in CGColorRef format from the UIColor class by referencing the cgColor property.
The advantage offered by UIColor, in addition to being object-oriented, is that it includes a range of convenience methods that can be used to create colors. For example, the following code uses the UIColor class to create the color red and then accesses the cgColor property for use as an argument to the setStrokeColor context method:
The color selection and transparency can be further refined using this technique by specifying additional components. For example:
let color = UIColor(red:1.0 green:0.3 blue:0.8 alpha:0.5)
As we can see, the use of UIColor avoids the necessity to create colorspaces and components when working with colors. Refer to the Apple documentation for more details on the range of methods provided by the UIColor class.
This chapter has covered some basic principles behind drawing two-dimensional graphics on iOS using the Quartz 2D API. Topics covered included obtaining the graphics context, implementing the draw method, and handling colors and transparency. In An iOS Graphics Tutorial using Core Graphics and Core Image, this theory will be implemented with examples of how to draw various shapes and images on an iOS device screen. Before moving on to the drawing tutorial, however, the next chapter will begin by exploring the Live Views feature of Interface Builder. Live Views are particularly useful when writing dynamic user interface code, such as drawing graphics.