iOS animer / forme morph du cercle au carré

J'essaie de changer un cercle en un carré et vice versa et je suis presque là. Cependant, il ne s'anime pas comme prévu. Je voudrais que tous les coins d'un carré soient animés / transformés en même time, mais ce que je reçois est le suivant:

entrez la description de l'image ici

J'utilise CAShapeLayer et CABasicAnimation afin d'animer la propriété shape.

Voici comment je crée le path du cercle:

 - (UIBezierPath *)circlePathWithCenter:(CGPoint)center radius:(CGFloat)radius { UIBezierPath *circlePath = [UIBezierPath bezierPath]; [circlePath addArcWithCenter:center radius:radius startAngle:0 endAngle:M_PI/2 clockwise:YES]; [circlePath addArcWithCenter:center radius:radius startAngle:M_PI/2 endAngle:M_PI clockwise:YES]; [circlePath addArcWithCenter:center radius:radius startAngle:M_PI endAngle:3*M_PI/2 clockwise:YES]; [circlePath addArcWithCenter:center radius:radius startAngle:3*M_PI/2 endAngle:M_PI clockwise:YES]; [circlePath closePath]; return circlePath; } 

Voici le path carré:

 - (UIBezierPath *)squarePathWithCenter:(CGPoint)center size:(CGFloat)size { CGFloat startX = center.x-size/2; CGFloat startY = center.y-size/2; UIBezierPath *squarePath = [UIBezierPath bezierPath]; [squarePath moveToPoint:CGPointMake(startX, startY)]; [squarePath addLineToPoint:CGPointMake(startX+size, startY)]; [squarePath addLineToPoint:CGPointMake(startX+size, startY+size)]; [squarePath addLineToPoint:CGPointMake(startX, startY+size)]; [squarePath closePath]; return squarePath; } 

J'applique le path du cercle à l'un des calques de ma vue, règle le remplissage, etc. Il dessine parfaitement. Ensuite, dans mon sélecteur gestureRecognizer, je crée et exécute l'animation suivante:

 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"]; animation.duration = 1; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; animation.fromValue = (__bridge id)(self.stateLayer.path); animation.toValue = (__bridge id)(self.stopPath.CGPath); self.stateLayer.path = self.stopPath.CGPath; [self.stateLayer addAnimation:animation forKey:@"animatePath"]; 

Comme vous pouvez le constater dans le circlePathWithCenter:radius: et squarePathWithCenter:size: Je suis la suggestion d'ici (pour avoir le même nombre de segments et de points de contrôle): Animation de changement de forme lisse

L'animation semble mieux alors dans le post d'en haut mais ce n'est toujours pas celui que je veux atteindre 🙁

Je sais que je peux le faire avec CALayer simple et ensuite définir le niveau approprié de cornerRadius pour faire un cercle de carré / rectangle et après cela animer la propriété cornerRadius pour le changer de cercle en carré mais je suis toujours extrêmement curieux si c'est même possible de le faire avec CAShapeLayer et l'animation de path .

Merci d'avance pour votre aide!

Après avoir joué avec lui pendant un petit moment dans la cour de récréation, j'ai remarqué que chaque arc ajoute deux segments à la trajectoire du Bézier, pas un seul. De plus, l'appel de closePath ajoute deux autres. Donc, pour garder le nombre de segments cohérents, j'ai fini par append de faux segments à mon path carré. Le code est dans Swift, mais je pense que cela n'a pas d'importance.

 func circlePathWithCenter(center: CGPoint, radius: CGFloat) -> UIBezierPath { let circlePath = UIBezierPath() circlePath.addArcWithCenter(center, radius: radius, startAngle: -CGFloat(M_PI), endAngle: -CGFloat(M_PI/2), clockwise: true) circlePath.addArcWithCenter(center, radius: radius, startAngle: -CGFloat(M_PI/2), endAngle: 0, clockwise: true) circlePath.addArcWithCenter(center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI/2), clockwise: true) circlePath.addArcWithCenter(center, radius: radius, startAngle: CGFloat(M_PI/2), endAngle: CGFloat(M_PI), clockwise: true) circlePath.closePath() return circlePath } func squarePathWithCenter(center: CGPoint, side: CGFloat) -> UIBezierPath { let squarePath = UIBezierPath() let startX = center.x - side / 2 let startY = center.y - side / 2 squarePath.moveToPoint(CGPoint(x: startX, y: startY)) squarePath.addLineToPoint(squarePath.currentPoint) squarePath.addLineToPoint(CGPoint(x: startX + side, y: startY)) squarePath.addLineToPoint(squarePath.currentPoint) squarePath.addLineToPoint(CGPoint(x: startX + side, y: startY + side)) squarePath.addLineToPoint(squarePath.currentPoint) squarePath.addLineToPoint(CGPoint(x: startX, y: startY + side)) squarePath.addLineToPoint(squarePath.currentPoint) squarePath.closePath() return squarePath } 

entrez la description de l'image ici

Je sais que c'est une vieille question mais cela pourrait aider quelqu'un.

Je pense qu'il vaut mieux animer le rayon du coin pour get cet effet.

  let v1 = UIView(frame: CGRect(x: 100, y: 100, width: 50, height: 50)) v1.backgroundColor = UIColor.green view.addSubview(v1) 

animation:

  let animation = CABasicAnimation(keyPath: "cornerRadius") animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) animation.fillMode = kCAFillModeForwards animation.isRemovedOnCompletion = false animation.fromValue = v1.layer.cornerRadius animation.toValue = v1.bounds.width/2 animation.duration = 3 v1.layer.add(animation, forKey: "cornerRadius") 

Je peux fortement reorder la bibliothèque CanvasPod , elle a aussi une animation "morph" prédéfinie et est facile à intégrer. Vous pouvez également consulter des exemples sur le site Web canvaspod.io .

Basé sur la réponse @Danchoys, ici c'est pour Objective-C.

info est un button de 60px et infoVC est le ViewController suivant poussé:

  UIBezierPath * maskPath = [UIBezierPath new]; [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(180) endAngle:DEGREES_TO_RADIANS(270) clockwise:true]; [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(270) endAngle:DEGREES_TO_RADIANS(0) clockwise:true]; [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(0) endAngle:DEGREES_TO_RADIANS(90) clockwise:true]; [maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(90) endAngle:DEGREES_TO_RADIANS(180) clockwise:true]; [maskPath closePath]; UIBezierPath * endPath = [UIBezierPath new]; [endPath moveToPoint:CGPointMake(0,0)]; [endPath addLineToPoint:endPath.currentPoint]; [endPath addLineToPoint:CGPointMake(w, 0)]; [endPath addLineToPoint:endPath.currentPoint]; [endPath addLineToPoint:CGPointMake(w, h)]; [endPath addLineToPoint:endPath.currentPoint]; [endPath addLineToPoint:CGPointMake(0, h)]; [endPath addLineToPoint:endPath.currentPoint]; [endPath closePath]; CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.frame = info.bounds; maskLayer.path = maskPath.CGPath; _infoVC.view.layer.mask = maskLayer; CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"path"]; animation.fromValue = (id)maskPath.CGPath; animation.toValue = (id)endPath.CGPath; animation.duration = 0.3f; [maskLayer addAnimation:animation forKey:nil]; [maskLayer setPath:endPath.CGPath];