This workshop will be retired on May 31, 2020.
Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Let's finish up by drawing the paths to complete the crosshairs
Updated Code Sample
Apple View Programming Guide for iOS
iOS Core-Graphic & Core-Image
Frame vs Bounds discussion from Stack Overflow
List of Core Graphics tutorials - Ray Wenderlich
Big Nerd Ranch Core Graphics series
Intro to 3D drawing in Core-Animation
Overview of Quartz 2D
SpriteKit Programming Guide
SceneKit Framework Reference
OpenGL and GLKit - Ray Wenderlich
Muppet Wiki - Sesame Street
I encourage you to try some of the following challenges and experiments with the Image Riddle code base:
- Customize the timing of the crosshairs animation by creating and configuring a CABasicAnimation object and adding it to the crosshairs layer
- Experiment with different stroke/fill colors and line-widths in the crosshairs layer
- Implement touchesMoved() so the crosshairs layer can be repositioned by dragging in addition to tapping.
- Remove the overriden UIResponder touch method(s), and reimplement the functionality using UIGestureRecognizers
- Experiment with the crosshairs layer transform property (this is an object of type CATransform3D). Try transforming in X, Y and Z
- Capture an image of the position the Riddle Maker has selected. I.e. capture the muppets AND the crosshairs in one image. Hint: you’ll need to render multiple layers into a UIGraphicsImageContext
All that's left to do is to work on changing a Red Square 0:00 into something that looks little more like crosshairs by drawing a Bezier path. 0:04 But before we do that, 0:08 we need to first set two more layer properties in the init method. 0:10 So let's go back up and over here will 0:13 say S=self.crosshairsLayer.stroke 0:18 color = UIcolor.blackColor.CG color. 0:24 And we'll say this is the crosshairs, let me make some more room, 0:30 crosshairs drawing color and then finally we'll also add a fill color. 0:36 And we'll set this to clearColor And 0:45 we'll say we're doing this because we only want an outline. 0:52 In core graphics there are fill colors that are used to fill the areas enclosed 0:59 by a Bezier path and a stroke color that is used to draw the lines. 1:03 For our crosshairs, we want to stroke blank lines for the crosshairs but 1:08 we still want to see our targets through the lines so 1:13 we're going to make the fill color a clear color. 1:16 One detail you may have noticed in the code is that we convert our 1:19 UI colors into CG colors when using them for layer properties. 1:23 The reason is that the core graphics framework 1:28 is a framework that both predates Cocoa Touch but is iOS and 1:31 also exists on the Mac desktop, which does graphics a little differently. 1:35 So UI color requires a conversion to be compatible with Quartz. 1:40 Okay, now that that's done it's time to do some path drawing. 1:45 So we're going to do this in drawRect and 1:49 we need to uncomment the method and get rid of this code. 1:53 In here, we'll begin our crosshairs with a circle. 2:02 So we'll say let circlePathBox 2:06 = CGRectInset. 2:13 We're going to create a rectangle circle path box that is slightly inset from 2:16 the edges of our shape layer. 2:21 So here for the Rect we'll say self.crosserslayer.bounds and 2:24 then for the inset X value we'll say 2:31 CROSSHAIRS_CIRCLE_INSET for both the X and Y inset. 2:35 Next we're going to use UIBezierPath paths oval in wrecked initializer which allows 2:44 us to pass in a CGRect to define a bounding box for a circular path. 2:48 So in here I will say let's circlePath = 2:54 UIBezierPath and we're going to pass in 2:59 an ovalInRect and say we're going to pass in these circlePathBox. 3:06 Finally we set the path property of the crosshairs layer to 3:11 the circle path that we just defined. 3:14 So we'll say 3:16 self.crosshairs.path = 3:19 circlePath.CGPath. 3:25 Okay, so now if we run this, we should see our familiar red box. 3:29 But inside you should see a black circle inset. 3:37 Now because my resolution is slightly lower and my simulator view is compressed, 3:40 it's a little bit distorted, but it should show up nicely on your end. 3:45 Now if you tap anywhere, it should cause both the red layer and 3:50 the inset black circle to animate to the new position. 3:54 Conveniently, animations of CA layers includes anything drawn 3:59 onto the layer using UIBezierPath as well. 4:03 Now we complete the crosshairs by adding cross lines over that circle that we 4:07 just drew. 4:11 So I'll say circle part of crosshairs. 4:15 That is a comment for this section right here. 4:22 And then for the cross, 4:32 we'll say cross part of crosshairs. 4:35 And for convenience, we're going to create a CGPoint variable called drawPoint. 4:40 So we'll say var drawPoint of type CGPoint. 4:45 Now this is going to serve as our drawing point, much like a pen tip. 4:52 Drawing straight lines with Bezier paths involves creating paths between 5:02 two points. 5:06 So again drawing point is going to act as a pen tip for these purposes. 5:07 To draw a vertical line down the middle of our layer, we're going to move the drawing 5:12 point to the horizontal center along the top edge of our layer, then we're going 5:16 to drop the point to the bottom edge and we'll add a line between those two paths. 5:22 So to do that let's say draw vertical first and again we're going to 5:27 move the drawing point to the horizontal center along the top edge. 5:32 So we'll say drawPoint = CGPointMake, and 5:37 we want to get to, for the X coordinate, 5:42 we want to get to the top edge so we'll say 5:46 self.crosshairslayer.bounds.size.width/2.0 and 5:50 then for the y coordinate, 0, 0. 5:57 So that puts us at the very top because the y is 0, 0 and 6:01 at the middle because we've divided the bound's width by two. 6:04 The move to point method now allows us to move this pen tip without drawing, 6:10 which is analogous to kinda picking up the pen and moving to a new point, and 6:15 then another method add line to point allows us to add a stroke path 6:20 between the two points. 6:24 So let's use those methods. 6:26 So we'll say circlePath.moveToPoint, drawPoint and 6:28 then now we want to change the drawPoint's Y coordinate. 6:34 Remember, at this point we're at the imagine a box, 6:39 we're at the very top edge and in the middle, and 6:42 we want to draw a line from that top edge to the bottom edge. 6:45 So we just need to change the y coordinate. 6:48 So we'll say, drawPoint.y = self.crosshairslayer.bounds.height. 6:51 Which gets us all the way to the bottom. 6:59 We'll add a comment, say move down. 7:01 And again we'll say circlePath. 7:05 Now we'll add a line to this point, we'll say drawPoint. 7:07 Now that the vertical point is done, to make the horizontal line, 7:15 the process is simply repeated. 7:18 But this time we're going to go from the left edge on the vertical center 7:20 to the right edge. 7:23 So another comment. 7:25 We'll say draw horizontal, again, because drawPoint is our pen tip more or less. 7:27 We'll move it to a new point. 7:35 So we'll say CGPointMake. 7:36 It's going to be a zero on the X coordinate cuz 7:39 we want to be on the left edge. 7:41 And for the y coordinate, 7:43 we'll say self.croshaLayer.bounds.size.height 7:44 divided/2. 7:52 Again, now that we're starting at that point, 7:55 we're going to move the Bezier path to this point. 7:58 So we'll say circlePath.moveToPoint. 8:00 And we'll see it moved to drawPoint. 8:03 Now again, because we're drawing a horizontal line, 8:07 we want to move to the opposite end of the box. 8:10 So we'll say, drawPoint.x because that's all we need to change. 8:13 We'll say self.crosshairsLayer.bounds.width and 8:18 then finally, we'll say circlePath and addLine between these two points. 8:22 And again, we'll specify drawPoint as a point. 8:28 The entire Bezier path now consists of an inset circle, 8:32 a vertical line and a horizontal line. 8:36 Once we assign this path to the crosshairs layer path and 8:40 run the application, we should see the full crosshair shape. 8:43 So we'll say self.crosshairLayer.path = circlePath.CGPath. 8:47 Let's give this a try, run the app, and 8:55 now you should see a perfect crosshair and when you move it, it should all animate. 9:00 The final step here is to comment out the red background color 9:06 property assignment in the init method, which is right here. 9:10 We now have a transparent repositionable animated crosshair suitable for 9:18 precise Muppet selection. 9:24 This mockup isn't a fully functioning game, of course. 9:27 But hopefully, it will give you ideas of what you can do in your 9:31 own apps with custom UI views, CA layers and quartz. 9:34 Thanks for watching. 9:39
You need to sign up for Treehouse in order to download course files.Sign up