2014-07-16 21 views
11

Cerco di cambiare un cerchio in un quadrato e viceversa e ci sono quasi. Tuttavia non si anima come previsto. Vorrei tutti gli angoli di un quadrato per essere animati/è mutato, allo stesso tempo, ma ciò che ottengo è il seguente:iOS animano/forma forma da cerchio a quadrato

enter image description here

utilizzare CAShapeLayer e CABasicAnimation per animare proprietà forma.

Ecco come ho creato il percorso cerchio:

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

Ecco il percorso piazza:

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

applico il percorso cerchio ad uno degli strati di mio avviso, impostare il riempimento etc. Disegna perfettamente. Poi nel mio selettore gestureRecognizer ho creare ed eseguire la seguente animazione:

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"]; 

Come si può notare nella circlePathWithCenter:radius: e squarePathWithCenter:size: seguo il suggerimento da qui (per avere lo stesso numero di segmenti e punti di controllo): Smooth shape shift animation

l'animazione sembra meglio poi nel post dall'alto, ma non è ancora quello che voglio raggiungere :(

so che posso farlo con semplice CALayer e quindi impostare un Il livello appropriato di cornerRadius per creare un cerchio fuori dal quadrato/rettangolo e dopo quello di animare la proprietà cornerRadius per spostarlo da un cerchio all'altro, ma sono comunque estremamente curioso se è addirittura possibile farlo con l'animazione CAShapeLayer e path.

Grazie in anticipo per l'aiuto!

+0

Sembra che stai avendo lo stesso problema di questa domanda [http://stackoverflow.com/questions/17429797/smooth-shape-shift-animation], basato sulle animazioni - potrebbe valere un'occhiata –

+0

hmm .. Potrebbe essere - conosco la domanda e ho seguito il suggerimento dalla risposta accettata, ma sono comunque un morto fine per me. Ho lo stesso numero di segmenti/punti di controllo che credo serva dato che la mia animazione è in una forma un po 'migliore di quella da lì ma il davanzale non ha idea di come migliorarlo. – fgeorgiew

risposta

7

Dopo aver giocato per un po 'nel parco giochi ho notato che ogni arco aggiunge due segmenti al percorso di Bezier, non solo uno. Inoltre, chiamando lo closePath ne aggiungi altri due. Quindi, per mantenere costante il numero di segmenti, ho finito con l'aggiungere segmenti falsi al mio percorso quadrato. Il codice è in Swift, ma penso che non abbia importanza.

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 
} 

enter image description here

+0

buona scoperta sui due punti, fatta una versione obiettivo-c. –

0

Consiglio vivamente la biblioteca CanvasPod, ma ha anche un predefinito di animazione "morph" ed è facile da integrare. Puoi anche dare un'occhiata agli esempi sul sito web canvaspod.io.

2

So che questa è una vecchia domanda, ma questo potrebbe aiutare qualcuno.

Penso che sia meglio animare il raggio dell'angolo per ottenere questo effetto.

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

animazione:

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") 
0

Sulla base di @Danchoys risposta, qui è per Objective-C.

informazioni un pulsante di 60px e infoVC è la prossima ViewController essere spinto:

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];