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:
- 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 ? - 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:
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:
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!
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)? –
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
Alla ricerca di una buona soluzione in Swift. – hugocarlmartin