iOS Recipes - Matt Drance [50]
CGPoint endPoint = CGPointMake(halfWidth, fullHeight);
CGPoint corner = CGPointMake(fullwidth, 0);
CGPoint leftCtrl = CGPointMake(-halfWidth, halfHeight/3);
CGPoint rightCtrl = CGPointMake(fullwidth*1.5, halfHeight/3);
UIBezierPath *pPath = [UIBezierPath bezierPath];
[pPath moveToPoint:startPoint];
[pPath addCurveToPoint:endPoint
controlPoint1:leftCtrl
controlPoint2:midPoint];
[pPath addCurveToPoint:startPoint
controlPoint1:midPoint
controlPoint2:rightCtrl];
[pPath addClip];
CGGradientRef gradient = [self gradientWithColor:self.innerColor
toColor:self.outerColor
count:3];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawLinearGradient(context,
gradient,
CGPointZero,
corner,
0);
pPath.lineWidth = self.lineThickness;
[self.strokeColor setStroke];
[pPath stroke];
}
Because the PRPetal class inherits from the base class PRPShapedView, we only need to override the drawRect: method. We build up the UIBezierPath from two cubic bezier curves that form the closed shape that we need to become a clipping Rect. The CGContextDrawLinearGradient function draws the gradient we created from the base class gradientWithColor method. Only then do we stroke the bezier path, clipping the gradient beneath it to match its shape.
GraphicsGarden/PRPSmile.m
- (void)drawRect:(CGRect)rect {
CGFloat halfHeight = self.bounds.size.height/2;
CGFloat halfWidth = self.bounds.size.width/2;
CGFloat fullHeight = self.bounds.size.height;
CGFloat fullwidth = self.bounds.size.width;
CGFloat radius = (halfWidth > halfHeight) ? halfHeight : halfWidth;
CGPoint midPoint = CGPointMake(halfWidth, halfHeight);
UIBezierPath *pPath = [UIBezierPath
bezierPathWithArcCenter: midPoint
radius: radius
startAngle: 0
endAngle: M_PI*2
clockwise: YES];
[pPath addClip];
CGGradientRef gradient = [self gradientWithColor:self.innerColor
toColor:self.outerColor
count:2];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawRadialGradient(context, gradient,
midPoint, 0,
midPoint, radius, 0);
pPath.lineWidth = self.lineThickness*1.7;
[self.strokeColor setStroke];
[pPath stroke];
// Eyes and Smile
[pPath removeAllPoints];
pPath.lineWidth = self.lineThickness;
[pPath moveToPoint:CGPointMake(halfWidth/2, halfHeight*1.3)];
[pPath addQuadCurveToPoint:CGPointMake(halfWidth*1.5, halfHeight*1.3)
controlPoint:CGPointMake(halfWidth, fullHeight*.91)];
[pPath stroke];
pPath = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(fullwidth/3-halfWidth*.1,
fullHeight/3,
halfWidth*.2,
halfHeight*.3)];
pPath.lineWidth = self.lineThickness;
[pPath fill];
[pPath stroke];
pPath = [UIBezierPath
bezierPathWithOvalInRect:CGRectMake(fullwidth/3*2-halfWidth*.1,
fullHeight/3,
halfWidth*.2,
halfHeight*.3)];
pPath.lineWidth = self.lineThickness;
[pPath fill];
[pPath stroke];
}
The PRPSmile class follows the pattern of the PRPetal class, except that we use an arc to draw a clipping circle, and we use the CGContextDrawRadialGradient function to create a radial gradient (colors radiate out from the center). The additional drawing code simply adds the eyes and smile to the graduated circle.
Now you have several views that you can use as building blocks for larger, more complex objects. In the next recipe, Recipe 24, Create Dynamic Images with Multiple Animations , that’s exactly what we’ll do.
Recipe 24 Create Dynamic Images with Multiple Animations
Problem
Core Animation simplifies the process of animating an object, making it move, rotate, or change size. But now you want to combine those techniques to create a more complex effect. Where do you start?
Solution
Making an object pulse and spin may not be something you need to do every day, but the technique here demonstrates how you can easily create complex effects by applying multiple animations to a single object (see Figure 30, Petals rotating and pulsing around the sun ).
GraphicsGarden/PRPSunshine.m
UIView *shineView = [[UIView alloc] initWithFrame:self.bounds];
self.shineLayer