天天看點

iPhone Graphics入門(一)

The series of articles is going to discuss creating graphics on the iPhone using the SDK. Part 1 will start out with the basics by drawing some simple 2D graphics. In later articles I plan to get into animation, using the accelerometers and maybe even a little OpenGL.

The sample application for this article is very simple. It is just a Cocoa Touch application with a single view. The view’s drawRect method contains all of the code. Again, this first article is very introductory.

All drawing is done directly onto a graphics context. For this example we are drawing on the current UI graphics context. You can also create your own graphics context and draw into it but this article won’t be getting into that process.

The first step is to get the graphics context and clear it. Technically since we are only really rendering this scene once and nothing is changing I don’t need to clear it but I will anyway.

1
2
3
4
5
      
-
 (
void
)
drawRect:
(
CGRect)
rect
{

    // Get the graphics context and clear it

    CGContextRef ctx =
 UIGraphicsGetCurrentContext(
)
;
    CGContextClearRect(
ctx, rect)
;
           

The UIGraphicsGetCurrentContext function returns the current graphics context for this UIView object. The CGContextRef value returned from this call is only valid until the drawRect method returns. You should not try to save the value in a variable and use it later.

CGContextClearRect does just what it says. It clears a rectangle. It actually makes the entire rectangle black. I haven’t found a way to clear to a different color.

The first object we are going to draw is a solid square colored red.

1
2
3
      
// Draw a red solid square

    CGContextSetRGBFillColor(
ctx, 255
, 0
, 0
, 1
)
;
    CGContextFillRect(
ctx, CGRectMake(
10
, 10
, 50
, 50
)
)
;
           

The CGContextSetRGBFillColor function is used to set the current fill color for the context. You give it values for red, green, blue and alpha. There are other ways to set the fill color but this is the easiest I’ve found. We’ll talk about the alpha value later.

You pass CGContextFillRect a rectangle created with CGRectMake and it will draw your rectangle using the current fill color. Nothing to it. Very simple stuff.

This code creates a solid circle colored green.

1
2
3
      
// Draw a green solid circle

    CGContextSetRGBFillColor(
ctx, 0
, 255
, 0
, 1
)
;
    CGContextFillEllipseInRect(
ctx, CGRectMake(
100
, 100
, 25
, 25
)
)
;
           

Again we use CGContextSetRBGFillColor to set the current fill color. CGContextFillEllipseInRect is passed a rectangle and will draw an ellipse within the bounds of the rectangle. We are giving it a square so our ellipse will end up being a circle.

The following code will draw the outline of a circle in blue:

1
2
3
      
// Draw a blue hollow circle

    CGContextSetRGBStrokeColor(
ctx, 0
, 0
, 255
, 1
)
;
    CGContextStrokeEllipseInRect(
ctx, CGRectMake(
200
, 200
, 50
, 50
)
)
;
           

This time we use CGContextSetRGBStrokeColor instead of CGContextSetRGBFillColor . The current stroke color is the color used to draw stroke type graphics. CGContextStrokeEllipseInRect is just like CGContextFillEllipseInRect except it draws a hollow circle instead of a filled circle.

This code draws the outline of square in yellow.

1
2
3
      
// Draw a yellow hollow rectangle

    CGContextSetRGBStrokeColor(
ctx, 255
, 255
, 0
, 1
)
;
    CGContextStrokeRect(
ctx, CGRectMake(
195
, 195
, 60
, 60
)
)
;
           

This code constructs a triangle from a set of three lines.

1
2
3
4
5
6
      
// Draw a purple triangle with using lines

    CGContextSetRGBStrokeColor(
ctx, 255
, 0
, 255
, 1
)
;
    CGPoint points[
6
]
 =
 {
 CGPointMake(
100
, 200
)
, CGPointMake(
150
, 250
)
,
                          CGPointMake(
150
, 250
)
, CGPointMake(
50
, 250
)
,
                          CGPointMake(
50
, 250
)
, CGPointMake(
100
, 200
)
 }
;
    CGContextStrokeLineSegments(
ctx, points, 6
)
;
           

The CGContextStrokeLineSegments function is passed an array of points and will draw lines between each pair of points.

The following code will draw the text string “TrailsintheSand.com”:

1
2
3
4
5
6
7
8
9
10
11
12
13
      
// Draw the text TrailsintheSand.com in light blue

    char
*
 text =
 "TrailsintheSand.com"
;
    CGContextSelectFont(
ctx, "Helvetica"
, 24.0
, kCGEncodingMacRoman)
;
    CGContextSetTextDrawingMode(
ctx, kCGTextFill)
;
    CGContextSetRGBFillColor(
ctx, 0
, 255
, 255
, 1
)
;
 
    CGAffineTransform xform =
 CGAffineTransformMake(

            1.0
,  0.0
,
            0.0
, -
1.0
,
            0.0
,  0.0
)
;
    CGContextSetTextMatrix(
ctx, xform)
;
 
    CGContextShowTextAtPoint(
ctx, 10
, 300
, text, strlen
(
text)
)
;
           

When drawing text we need a font. In this case we are selecting a 24 point Helvetica font into the current context with the CGContextSelectFont function.

CGContextSetTextDrawingMode is used to set how the text will be drawn. In this case it is set to kCGTextFill which means the text will be filled with the current fill color. You can draw the text outlined using kCGTextStroke or both filled and outlined with kCGTextFillStroke .

Since we are using kCGTextFill we need to set a fill color.

CGContextShowTextAtPoint draws the text at the specified x,y coordinate within the view. Notice that it takes a C style null terminated string.

You’ll notice that I skipped the call to CGAffineTransformMake function call. If you run this code without it your text will be drawn up-side down but in the correct position on the screen. The CGAffineTransformMake function creates a transformation matrix and the CGContextSetTextMatrix will cause this matrix to be applied to all text drawn on the context. The matrix above will cause to text to be flipped so it is right-side up. It seems strange to me that the default would be upside down. Apparently fonts are stored with a different coordinate system. You can also use transformation matricies to do things like rotate and scale your text.

Now we are going to draw a filled gray transparent rectangle over some of the other graphics that we’ve already drawn.

1
2
3
      
// Draw a transparent filled circle over other objects

    CGContextSetRGBFillColor(
ctx, 200
, 200
, 200
, 0.5
)
;
    CGContextFillEllipseInRect(
ctx, CGRectMake(
100
, 200
, 150
, 150
)
)
;
           

The last parameter passed to CGContextSetRGBFillColor is the alpha value and controls the transparency of what is drawn. This value ranges from 0 to 1 with 0 being completely transparent and 1 being completely opaque.

The last graphics example is drawing an image.

1
2
3
4
5
6
7
8
9
10
      
// Load image from applicaiton bundle

    NSString
*
 imageFileName =
 [
[
[
NSBundle
 mainBundle]
 resourcePath]
 stringByAppendingPathComponent:
@
"iphone_sdk.png"
]
;
    CGDataProviderRef provider =
 CGDataProviderCreateWithFilename(
[
imageFileName UTF8String]
)
;
    CGImageRef image =
 CGImageCreateWithPNGDataProvider(
provider, NULL
, true
, kCGRenderingIntentDefault)
;
    CGDataProviderRelease(
provider)
;
 
    // Draw image

    CGContextDrawImage(
ctx, CGRectMake(
200
, 0
, 100
, 100
)
, image)
;
    CGImageRelease(
image)
;
}
           

The image we are going to draw has been added as a resouce to the project (just like a source file) and will be compiled into the application bundle. We get a reference to the bundle by calling the mainBundle: method of NSBundle . Then we get the resourcePath by calling the resourcePath: method on the mainBundle. This returns an NSString object that we call stringByAppendingPathComponent: on passing it the file name to get the full path to the file name.

Now that we have the file name we create a CGDataProviderRef object using the CGDataProviderCreateWithFilename function.

Now we can get the actual CGImageRef object that we’ll use to draw the image. The CGImageCreateWithPNGDataProvider function takes our provider and turns it into an image.

We are done with the provider so we call CGDataProviderRelease to release its memory and resources.

Finally we can call the CGContextDrawImage function to actually draw the image on the graphics context. We pass it a rectangle that the image will be drawn into. The image will be automatically resized to fit the rectangle with no regard to the image aspect ratio.

Lastly we use CGImageRelease to free up the image.

The only problem with this code is that the image will be drawn up-side down. I assume this is the same reason fonts default to being drawn up-side down. I’ll talk about how to correct this in the next article.

Screenshot:

iPhone Graphics入門(一)

The next article in this series will go into more detail on drawing images.

繼續閱讀