2013-11-21 9 views
17

Ho un progetto in cui sto animando un UIBezierPath in base a una serie di progressi. BezierPath ha la forma di un cerchio e giace in una UIView e l'animazione viene eseguita in drawRect usando CADisplayLink in questo momento. In poche parole, in base a un avanzamento impostato x, il percorso dovrebbe estendersi radialmente (se x è maggiore di prima) o ridursi (se x è più piccolo).Animazione di una circolare UIBezierPath

self.drawProgress = (self.displayLink.timestamp - self.startTime)/DURATION; 

CGFloat startAngle = -(float)M_PI_2; 
CGFloat stopAngle = ((self.x * 2*(float)M_PI) + startAngle); 
CGFloat currentEndAngle = ((self.oldX * 2*(float)M_PI) + startAngle); 
CGFloat endAngle = currentEndAngle-((currentEndAngle-stopAngle)*drawProgress); 

UIBezierPath *guideCirclePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; 

questo è nel caso di x contrazione dal nostro ultimo aggiornamento. Le questioni che sto vivendo in realtà sono pochi:

  1. La forma sempre inizia a disegnare a 45 ° (a meno che non ruotare la vista). Non ho trovato alcun modo per cambiare questo, e l'impostazione di startAngle a -45º non fa alcuna differenza in realtà perché "scatta" sempre a 45. C'è qualcosa che posso fare al riguardo, o devo ricorrere ad altri metodi di disegno ?
  2. C'è qualche altro modo per animare queste cose? Ho letto molto sull'utilizzo di CAShapeLayer ma non ho ancora compreso la reale differenza (in termini di inconvenienti e vantaggi) nell'utilizzo di questi due metodi. Se qualcuno potesse chiarire sarei molto grato!

UPDATE: ho migrato il codice verso CAShapeLayer invece, ma ora sono di fronte a un problema diverso. E 'meglio descritta con questa immagine:

enter image description here

Cosa accade è che quando si suppone che il livello a ridursi, la linea esterna sottile è ancora lì (indipendentemente dalla direzione di movimento). E quando la barra si restringe, il delta di 1- x non viene rimosso a meno che non crei esplicitamente una nuova forma bianca su di esso. Il codice per questo segue. Qualche idea?

UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:stopAngle clockwise:YES]; 
CAShapeLayer *circle = [CAShapeLayer layer]; 
circle.path = [circlePath CGPath]; 
circle.strokeStart = 0; 
circle.strokeEnd = 1.0*self.progress; 

// Colour and other customizations here. 

if (self.progress > self.oldProgress) { 
    drawAnimation.fromValue = @(1.0*self.oldProgress); 
    drawAnimation.toValue = @(circle.strokeEnd); 
} else { 
    drawAnimation.fromValue = @(1.0*self.oldProgress); 
    drawAnimation.toValue = @(1.0*self.progress); 
    circle.strokeEnd = 1.0*self.progress; 
} 

drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; //kCAMediaTimingFunctionEaseIn 
[circle addAnimation:drawAnimation forKey:@"strokeEnd"]; 

UPDATE 2: ho risolti la maggior parte degli altri insetti. Venuto fuori era solo io essere piuttosto sciocco tutto il tempo e sovraccompagnare l'intera animazione (per non parlare moltiplicando per 1 ovunque, cosa?). Ho fatto una gif del bug non riesco a risolvere:

radial control glitch

Tutte le idee?

UPDATE 3: (e chiusura). Sono riuscito a sbarazzarmi del bug chiamando

[self.layer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]; 

E ora tutto funziona come dovrebbe. Grazie per tutto l'aiuto!

+0

Stai cercando di fare qualcosa di simile a [questo (crea un cerchio completo aumentando l'angolo di un segmento da 0 a 360 gradi)] (http://stackoverflow.com/a/8021051/608157)? –

+0

Sono passato all'utilizzo di CAShapeLayer + CABasicAnimation poiché sembra esserci una scelta più valida, in parte perché è possibile utilizzare le proprietà consigliate da Duncan. – hav

+0

Alla ricerca di una buona soluzione in Swift. – hugocarlmartin

risposta

10

L'utilizzo di CAShapeLayer è molto più semplice e pulito. Il motivo è che CAShapeLayer include proprietà strokeStart e strokeEnd. Questi valori vanno da 0 (l'inizio del percorso) a 1 (la fine del percorso) e sono animabili.

Cambiandoli puoi facilmente disegnare qualsiasi arco della tua cerchia (o qualsiasi parte di un percorso arbitrario, per quella materia.) Le proprietà sono animabili, quindi puoi creare un'animazione di una sezione o sezione di torta crescente o restringente di una forma ad anello. È molto più semplice e performante rispetto all'implementazione del codice in drawRect.

+1

Questo semplifica davvero molto le cose, e ho passato il codice a una soluzione basata su CAShapeLayer e CABasicAnimation, quindi grazie per questo! Tuttavia, ora sto vivendo una stranezza diversa ... – hav

+1

E che stranezza è? –