Mi piacerebbe animare una forma mentre transita da un cerchio ad un triangolo con angoli arrotondati.Animare un cerchio CAShapeLayer in un triangolo con angoli arrotondati
TL; DR: Come faccio ad animare una s CAShapeLayer
' path
tra due CGPath
forme? So che devono avere lo stesso numero di punti di controllo, ma penso che lo stia facendo - cosa c'è di sbagliato in questo codice?
Gli stati iniziale e finale sarebbe simile a questa: transition http://clrk.it/4vJS+
Ecco quello che ho provato finora: sto usando un CAShapeLayer
, e animando un cambiamento nella sua proprietà path
.
Secondo il documentation (sottolineatura mia):
L'oggetto percorso può essere animati utilizzando una delle sottoclassi concrete di
CAPropertyAnimation
. I percorsi interpoleranno come una miscela lineare dei punti "on-line"; i punti "off-line" possono essere interpolati non linearmente (per esempio per preservare la continuità della derivata della curva). Se i due percorsi hanno un numero diverso di punti di controllo o segmenti, i risultati non sono definiti.
Nel tentativo di ottenere il cerchio e triangolo per avere lo stesso numero di punti di controllo, li feci entrambe le forme a quattro punte: il cerchio è un rettangolo fortemente arrotondato, e il triangolo è "nascosto" un quarto punto di controllo su un lato.
Ecco il mio codice:
self.view.backgroundColor = .blueColor()
//CREATE A CASHAPELAYER
let shape = CAShapeLayer()
shape.frame = CGRect(x: 50, y: 50, width: 200, height: 200)
shape.fillColor = UIColor.redColor().CGColor
self.view.layer.addSublayer(shape)
let bounds = shape.bounds
//CREATE THE SQUIRCLE
let squareRadius: CGFloat = CGRectGetWidth(shape.bounds)/2
let topCorner = CGPointMake(bounds.midX, bounds.minY)
let rightCorner = CGPointMake(bounds.maxX, bounds.midY)
let bottomCorner = CGPointMake(bounds.midX, bounds.maxY)
let leftCorner = CGPointMake(bounds.minX, bounds.midY)
let squarePath = CGPathCreateMutable()
let squareStartingPoint = midPoint(leftCorner, point2: topCorner)
CGPathMoveToPoint(squarePath, nil, squareStartingPoint.x, squareStartingPoint.y)
addArcToPoint(squarePath, aroundPoint: topCorner, onWayToPoint: rightCorner, radius: squareRadius)
addArcToPoint(squarePath, aroundPoint: rightCorner, onWayToPoint: bottomCorner, radius: squareRadius)
addArcToPoint(squarePath, aroundPoint: bottomCorner, onWayToPoint: leftCorner, radius: squareRadius)
addArcToPoint(squarePath, aroundPoint: leftCorner, onWayToPoint: topCorner, radius: squareRadius)
CGPathCloseSubpath(squarePath)
let square = UIBezierPath(CGPath: squarePath)
//CREATE THE (FAKED) TRIANGLE
let triangleRadius: CGFloat = 25.0
let trianglePath = CGPathCreateMutable()
let triangleStartingPoint = midPoint(topCorner, point2: rightCorner)
let startingPoint = midPoint(topCorner, point2: leftCorner)
CGPathMoveToPoint(trianglePath, nil, startingPoint.x, startingPoint.y)
let cheatPoint = midPoint(topCorner, point2:bottomCorner)
addArcToPoint(trianglePath, aroundPoint: topCorner, onWayToPoint: cheatPoint, radius: triangleRadius)
addArcToPoint(trianglePath, aroundPoint: cheatPoint, onWayToPoint: bottomCorner, radius: triangleRadius)
addArcToPoint(trianglePath, aroundPoint: bottomCorner, onWayToPoint: leftCorner, radius: triangleRadius)
addArcToPoint(trianglePath, aroundPoint: leftCorner, onWayToPoint: topCorner, radius: triangleRadius)
CGPathCloseSubpath(trianglePath)
let triangle = UIBezierPath(CGPath: trianglePath)
shape.path = square.CGPath
... e più tardi, in viewDidAppear
:
let animation = CABasicAnimation(keyPath: "path")
animation.fromValue = self.square.CGPath
animation.toValue = self.triangle.CGPath
animation.duration = 3
self.shape.path = self.triangle.CGPath
self.shape.addAnimation(animation, forKey: "animationKey")
Ho due piccole funzioni rapide per rendere il codice più leggibile:
func addArcToPoint(path: CGMutablePath!, aroundPoint: CGPoint, onWayToPoint: CGPoint, radius: CGFloat) {
CGPathAddArcToPoint(path, nil, aroundPoint.x, aroundPoint.y, onWayToPoint.x, onWayToPoint.y, radius)
}
func midPoint(point1: CGPoint, point2: CGPoint) -> CGPoint {
return CGPointMake((point1.x + point2.x)/2, (point1.y + point2.y)/2)
}
Il mio attuale risultato è il seguente:
NOTA: Sto cercando di costruire il cerchio di una piazza molto arrotondato, nel tentativo di ottenere lo stesso numero di punti di controllo in forma vettoriale. Nel GIF sopra, il raggio dell'angolo è stato ridotto per rendere più visibile la trasformazione.
Cosa pensi che stia succedendo? In quale altro modo potrei ottenere questo effetto?
provare a realizzare entrambe le forme con molti segmenti di linea retta? – nielsbot
in realtà, sei sicuro di utilizzare correttamente addArcToPoint()? – nielsbot
(Non ho il parametro * path * per aggiungereArcToPoint() per essere facoltativo) – nielsbot