2014-07-16 117 views
11

我嘗試將圓形更改爲正方形,反之亦然,並且我快到了。然而,它並不像預期那樣動畫。我想一個正方形的各個角落進行動畫/在同一時間演變,但我得到的是以下幾點:從圓形到方形的iOS動畫/變形形狀

enter image description here

我以動畫形狀財產使用CAShapeLayerCABasicAnimation

這裏是我創建的圈子路徑:

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

下面是方形路徑:

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

我申請的圓圈路徑我的看法的一層,設置填充等。它完美地繪製。 然後在我gestureRecognizer選擇創建並運行下面的動畫:

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

正如你可以在circlePathWithCenter:radius:squarePathWithCenter:size:我按照建議從這裏看到(有相同數量的段和控制點): Smooth shape shift animation

動畫看起來更好,然後從上面的文章,但它仍然不是一個我想要達到:(

我知道,我可以用簡單的CALayer做到這一點,然後設置一個cornerRadius的適當等級使圓形超出正方形/矩形,之後使用動畫cornerRadius屬性將其從圓形更改爲方形,但如果甚至可以使用CAShapeLayerpath動畫完成此操作,我仍然非常好奇。

在此先感謝您的幫助!

+0

它看起來像你有同樣的問題,因爲這問題[http://stackoverflow.com/questions/17429797/smooth-shape-shift-animation],基於動畫 - 可能值得一看 –

+0

嗯..它可能是 - 我知道這個問題,並遵循接受的答案的建議,但我仍然是一個死亡爲我結束。我有相同數量的細分/控制點,我認爲它們有幫助,因爲我的動畫形狀稍好一些,但是從那裏開始的動畫卻沒有線索如何改進。 – fgeorgiew

回答

7

在操場上玩了一會兒之後,我注意到每條弧線都在bezier路徑上添加了兩段,而不僅僅是一段。此外,致電closePath增加了兩個。所以爲了保持細分的數量一致,我最終在我的方形路徑中添加了假段。代碼在Swift中,但我認爲這並不重要。

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

好的發現重新提出了兩點,做了一個客觀的c版本。 –

0

我強烈推薦圖書館CanvasPod,它也有一個預定義的「變身」動畫和易於集成。您也可以在網站canvaspod.io上查看示例。

2

我知道這是一個古老的問題,但這可能有助於某人。

我認爲它更好地動畫角落半徑來獲得這種效果。

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

動畫:

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

基於@Danchoys答案,在這裏它是Objective-C的。

信息是60像素和infoVC的按鈕是下一個視圖控制器推:

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