48 votes

iPhone Core Animation - Tracer un cercle

Je souhaite créer une animation. La meilleure façon que je peux expliquer ce que c'est si vous pouvez imaginer le dessin d'un cercle. Il commence par le haut ou 12 heures et attire des aiguilles d'une montre tout le chemin jusqu'à ce qu'il devient un cercle complet sur l'espace de 10 secondes.

Le placard je suis venu c'est pour tracer un point en rotation autour d'un point central à l'aide de Core Animation (à l'aide de l'exemple de code ici). Mais je suis à une perte sur la façon de dessiner le cercle? Toutes les suggestions sont les bienvenues.

Merci Beaucoup :)

161voto

David Rönnqvist Points 25290

Ce que vous devriez vraiment faire est d' animer le coup de CAShapeLayer où la trajectoire est un cercle. Cela va être accéléré en utilisant la Base de l'Animation et de l'est moins salissant ensuite faire partie d'un cercle en drawRect:.

Le code ci-dessous va créer un cercle d'un calque de forme dans le centre de l'écran et d'animer la course de la dans le sens horaire de sorte qu'il semble que si elle est en cours d'élaboration. Vous pouvez bien sûr utiliser n'importe quelle forme que vous souhaitez. (Vous pouvez lire cet article sur Ole Begemanns blog pour en savoir plus sur la façon d'animer le coup d'une couche de forme.)

Remarque: que le stoke propriétés ne sont pas les mêmes que la frontière propriétés de la couche. Pour modifier la largeur de la course, vous devez utiliser "largeur de raie" au lieu de "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"];

8voto

matt Points 350

Voici une autre solution au problème, basé sur @David réponse. Cette approche permet de définir la direction du cercle de l'animation, et offre un peu plus de contrôle. Edit: j'ai écrit un blog sur comment dessiner un cercle avec Swift, dont je vais essayer de tenir à jour avec les bêtas. Vérifier si le code ci-dessous ne fonctionne pas pour vous.

let radius = 100.0

// Create the circle layer
var circle = CAShapeLayer()

// Set the center of the circle to be the center of the view
let center = CGPointMake(CGRectGetMidX(self.frame) - radius, CGRectGetMidY(self.frame) - radius)

let fractionOfCircle = 3.0 / 4.0

let twoPi = 2.0 * Double(M_PI)
// The starting angle is given by the fraction of the circle that the point is at, divided by 2 * Pi and less
// We subtract M_PI_2 to rotate the circle 90 degrees to make it more intuitive (i.e. like a clock face with zero at the top, 1/4 at RHS, 1/2 at bottom, etc.)
let startAngle = Double(fractionOfCircle) / Double(twoPi) - Double(M_PI_2)
let endAngle = 0.0 - Double(M_PI_2)
let clockwise: Bool = true

// `clockwise` tells the circle whether to animate in a clockwise or anti clockwise direction
circle.path = UIBezierPath(arcCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: clockwise).CGPath

// Configure the circle
circle.fillColor = UIColor.blackColor().CGColor
circle.strokeColor = UIColor.redColor().CGColor
circle.lineWidth = 5

// When it gets to the end of its animation, leave it at 0% stroke filled
circle.strokeEnd = 0.0

// Add the circle to the parent layer
self.layer.addSublayer(circle)

// Configure the animation
var drawAnimation = CABasicAnimation(keyPath: "strokeEnd")
drawAnimation.repeatCount = 1.0

// Animate from the full stroke being drawn to none of the stroke being drawn
drawAnimation.fromValue = NSNumber(double: fractionOfCircle)
drawAnimation.toValue = NSNumber(float: 0.0)

drawAnimation.duration = 30.0

drawAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)

// Add the animation to the circle
circle.addAnimation(drawAnimation, forKey: "drawCircleAnimation")

3voto

bennythemink Points 2446

J'ai une solution à ce problème, code ci-dessous. Il semble que je me suis trompé dans mon explication du problème en question, alors reformulez-le comme une autre question à laquelle on a répondu avec la solution correcte, voir ici

merci à tous pour leurs conseils!

 -(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);
}
 

0voto

bennythemink Points 2446

Ok j'ai un correctif partiel. J'ai trouvé le code suivant qui dessine des segments de cercle. Il s’agit essentiellement d’une sous-classe UIView qui tire son drawRect à chaque mise à jour de ses progrès. La seule question que je me pose maintenant est de savoir comment je pourrais le changer pour qu'au lieu de dessiner des coupes ou des coupes, il dessine simplement le trait de cercle.

 -(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);
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X