Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iPhone: Drawing a curved line until it becomes a circle animation

I wish to draw a curved line until it makes a full rotation and joins to become a complete circle, just the circle outline, not filled. This has to be animated over a number of seconds.

Can anyone point me in the right direction? I already asked a similar question to this but I worded it incorrectly so everyone had a hard time understanding what I meant and thus it got lost in the sea of questions.

Many Thanks for any help

[edit]

I'm currently sub-classing UIView and overriding drawRect. I found code to draw a filled circle but I only require the stroke.

- (void)drawRect:(CGRect)rect {
// Drawing code

CGRect allRect = self.bounds;
CGRect circleRect = CGRectInset(allRect, 2.0f, 2.0f);

CGContextRef context = UIGraphicsGetCurrentContext();

// Draw background
CGContextSetRGBStrokeColor(context, self.strokeValueRed, self.strokeValueGreen, self.strokeValueBlue, self.strokeValueAlpha); // white
CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 0.1f); // translucent white
CGContextSetLineWidth(context, self.lineWidth);
CGContextFillEllipseInRect(context, circleRect);
CGContextStrokeEllipseInRect(context, circleRect);

// Draw progress
CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2);
CGFloat radius = (allRect.size.width - 4) / 2;
CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees
CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle;
CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); // white
CGContextMoveToPoint(context, center.x, center.y);
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0);
CGContextClosePath(context);
CGContextFillPath(context);
}

[edit #2]

I changed the code to remove all the fill references but now its not drawing anything :( any ideas?

- (void)drawRect:(CGRect)rect
{
// Drawing code

CGRect allRect = self.bounds;
CGContextRef context = UIGraphicsGetCurrentContext();

// Draw background
CGContextSetRGBStrokeColor(context, self.strokeValueRed, self.strokeValueGreen, self.strokeValueBlue, self.strokeValueAlpha); // white
CGContextSetLineWidth(context, 5);

// Draw progress
CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2);
CGFloat radius = (allRect.size.width - 4) / 2;
CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees
CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle;
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0);
CGContextStrokePath(context);
}

[edit #3] Solution

Right I feel like a right dickhead! the problem was that the stroke colour values were not initialised meaning that line was being draw but obviously could not see it!!

like image 961
bennythemink Avatar asked Nov 04 '11 04:11

bennythemink


2 Answers

This is the same answer as I gave to your other question here.

What you really should do is to animate the stroke of a CAShapeLayer where the path is a circle. This will be accelerated using Core Animation and is less messy then to draw part of a circle in -drawRect:.

The code below will create a circle shape layer in the center of the screen and animate the stroke of it clockwise so that it looks as if it is being drawn. You can of course use any shape you'd like. (You can read this article on Ole Begemanns blog to learn more about how to animate the stroke of a shape layer.)

Note: that the stoke properties are not the same as the border properties on the layer. To change the width of the stroke you should use "lineWidth" instead of "borderWitdh" etc.

// Set up the shape of the circle
int radius = 100;
CAShapeLayer *circle = [CAShapeLayer layer];
// Make a circular shape
circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius) 
                                         cornerRadius:radius].CGPath;
// Center the shape in self.view
circle.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius, 
                              CGRectGetMidY(self.view.frame)-radius);

// Configure the apperence of the circle
circle.fillColor = [UIColor clearColor].CGColor;
circle.strokeColor = [UIColor blackColor].CGColor;
circle.lineWidth = 5;

// Add to parent layer
[self.view.layer addSublayer:circle];

// Configure animation
CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
drawAnimation.duration            = 10.0; // "animate over 10 seconds or so.."
drawAnimation.repeatCount         = 1.0;  // Animate only once..

// Animate from no part of the stroke being drawn to the entire stroke being drawn
drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
drawAnimation.toValue   = [NSNumber numberWithFloat:1.0f];

// Experiment with timing to get the appearence to look the way you want
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

// Add the animation to the circle
[circle addAnimation:drawAnimation forKey:@"drawCircleAnimation"];
like image 117
David Rönnqvist Avatar answered Oct 22 '22 11:10

David Rönnqvist


Take out everything that says Fill.

Change the CGContextFillPath at the end to CGContextStrokePath.

Take out the CGContextMoveToPoint and CGContextClosePath near the end. Those just outline the straight sides of the wedge.

You might have to change the CGContextMoveToPoint to move to the start point of the arc instead of the center, instead of taking it out.

like image 42
morningstar Avatar answered Oct 22 '22 10:10

morningstar