2015-05-20 145 views
7

我想在從一個圓轉換爲圓角三角形時創建一個形狀的動畫。將一個CAShapeLayer圓動畫成一個圓角三角形

TL; DR:如何在兩個CGPath形狀之間創建CAShapeLayerpath動畫?我知道他們需要有相同數量的控制點,但我認爲我正在這麼做 - 這段代碼有什麼問題?

的開始和結束時的狀態會是這個樣子: transition http://clrk.it/4vJS+

這裏是我試過到目前爲止:我使用的是CAShapeLayer,和動畫在其path屬性的變化。

按照documentation(重點煤礦):

的路徑對象可以使用任何CAPropertyAnimation的具體子類的動畫。路徑將作爲「在線」點的線性混合插值; 「離線」點可以非線性地內插(例如,以保持曲線導數的連續性)。 如果兩個路徑具有不同數量的控制點或分段,則結果未定義。

在試圖得到圓形和三角形有相同數量的控制點,我讓他們都四角形狀:圓是一個重圓角矩形,三角形被「隱藏」一邊是第四個控制點。

這裏是我的代碼:

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 

...,後來,在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") 

我有兩個小巧的功能使代碼更易讀:

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) 
} 

我目前的結果是這樣的:

triangle-to-square

注:我試圖打造出圓一個非常全面的廣場,企圖得到的矢量形狀相同數量的控制點。在上面的GIF中,拐角半徑已經減小,以使變形更明顯。

你認爲怎麼回事?我可以怎樣才能達到這個效果?

+0

嘗試使用很多直線段代替兩種形狀? – nielsbot

+0

實際上,你確定你正在使用addArcToPoint()嗎? – nielsbot

+0

(我不叮囑*路徑*參數addArcToPoint()是可選的) – nielsbot

回答

6

因爲addArcToPoint()跳過創建一個線段,如果路徑的當前點和它的第一個參數相等,您不會結束相同數量的控制點。

從它的文檔(重點煤礦):

如果當前點和圓弧(起點)不相等的第一切點,石英追加從當前的直線段指向第一個切點。

在三角使代碼這兩個電話不會產生線段,而相應的電話撥打了方圓形會:

addArcToPoint(trianglePath, aroundPoint: cheatPoint, onWayToPoint: bottomCorner, radius: triangleRadius) 
addArcToPoint(trianglePath, aroundPoint: bottomCorner, onWayToPoint: leftCorner, radius: triangleRadius) 

可以手動創建的線條,不過,通過調用CGPathAddLineToPoint 。你可以使用CGPathApplierFunction來檢查你的工作,這可以讓你列舉控制點。


也~~~我可能會建議紡顯示鏈接,寫一個函數指定爲每t ∈ [0, 1]所需的形狀很可能將是一個更清晰,更易於維護的解決方案。

+0

非常感謝!是的,這將是一個交互式的循環 - 你將它拖動到左邊,圓形變成了一個箭頭,把它拖到右邊,它就會以另一種方式 - 所以我一定要寫這個功能! – bryanjclark

+1

Facebook的Pop框架是用曲線,鏈接等構建動畫的一種非常好的方式,可以使用這些功能(請參閱https://github.com/facebook/pop/blob/master/pop/POPAnimatableProperty.h)。 –