2016-04-12 32 views
1

我想實現一個圓形的進度,並且可以動態設置進度值。代碼如下:CAShapeLayer動畫在我設置的時間非常短時閃動

- (CGPoint)center { 
    return CGPointMake(self.view.frame.origin.x + self.view.frame.size.width/2.0, 
       self.view.frame.origin.y + self.view.frame.size.height/2.0); 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    // Do any additional setup after loading the view. 

    CGMutablePathRef roundPath = CGPathCreateMutable(); 
    CGPathAddArc(roundPath, NULL, self.center.x, self.center.y, 
      20, 
      2 * M_PI + M_PI_2, 
      M_PI_2, 
      YES); 

    CAShapeLayer *backgroundLayer = [CAShapeLayer layer]; 
    backgroundLayer.frame = self.view.layer.bounds; 
    backgroundLayer.path = roundPath; 
    backgroundLayer.strokeColor = [[NSColor blueColor] CGColor]; 
    backgroundLayer.fillColor = nil; 
    backgroundLayer.lineWidth = 10.0f; 
    backgroundLayer.lineJoin = kCALineJoinBevel; 
    [self.view.layer addSublayer:backgroundLayer]; 

    CAShapeLayer *pathLayer = [CAShapeLayer layer]; 
    pathLayer.frame = self.view.layer.bounds; 
    pathLayer.path = roundPath; 
    pathLayer.strokeColor = [[NSColor whiteColor] CGColor]; 
    pathLayer.fillColor = nil; 
    pathLayer.lineWidth = 10.0f; 
    pathLayer.lineJoin = kCALineJoinBevel; 
    [self.view.layer addSublayer:pathLayer]; 

    self.pathLayer = pathLayer; 
    [self start]; 
} 

- (void)start { 
    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 
    pathAnimation.duration = 0.01; 
    pathAnimation.fromValue = [NSNumber numberWithFloat:self.progress]; 
    pathAnimation.toValue = [NSNumber numberWithFloat:self.progress+0.01]; 
    [self.pathLayer setStrokeEnd:self.progress + 0.01]; 
    [pathAnimation setDelegate:self]; 
    [self.pathLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; 
} 

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { 
    self.progress += 0.01; 
    if (self.progress < 1.0) { 
    [self start]; 
    } 
} 

我發現,當我設定的時間是0.1F或更大,它會工作right.But如果我設定的時間是0.01F,動畫將不會從正確的值開始,它會從更大的值開始動畫,然後降低到正確的值。所以整個動畫總是閃爍,任何人都有同樣的問題或知道爲什麼?非常感謝!

回答

3

originaluser2可能是對的具體原因,但這種設計是不正確的。

在60fps時,一幀是0.0167s。您要求在不到一幀的時間內對變化進行動畫製作。每個動畫都有自己的媒體時間(kCAMediaTimingFunctionDefault),這意味着您可以通過動畫創建複雜的加速/減速速度。而且你的計時無論如何都會不穩定,因爲你在每個步驟中都會遇到一些小錯誤(根據許多因素,animationDidStop可能需要稍微不同的時間來運行)。動畫的全部要點是你不需要做這種東西。這就是爲什麼你有一個動畫引擎。

隨着時間的推移,您只需要動畫progress即可。不要嘗試注入許多額外的動畫步驟。注入步驟是動畫引擎的功能。

CALayer無論如何都是爲你做這些東西的大部分。您不需要爲此創建明確的動畫;只是使用隱式。喜歡的東西(未經測試,未編譯):

​​
+0

一個非常好的點(+1)......不能相信我錯過了一些顯而易見的原因!我想我認爲OP有一個使用重複動畫的奇妙理由......我唯一能想到的就是能夠暫停動畫 - 但如果OP需要的話,可以只使用一個顯式動畫。 – Hamish

+0

真的非常感謝您的幫助,您爲我節省了很多時間。 – melody5417

+0

感謝您的幫助,我只知道我應該點擊檢查標記接受的答案。 – melody5417

1

作爲Rob says,添加重複的動畫並不是最好的主意。他的解決方案可能會很好地爲你工作。但是,如果你還在使用重複的動畫堅持,這裏是您當前的代碼修復:


的問題是你調用這行代碼之前你添加動畫。當你來到添加您的明確動畫

[self.pathLayer setStrokeEnd:self.progress + 0.01]; 

這將創建層上的隱式動畫,所以 - 這將導致問題(你觀察閃爍)。

解決的方法是在之後開始動畫,更新CATransaction內的模型圖層。您還需要將disableActions設置爲YES以防止生成隱式動畫。

例如:

- (void)start { 
    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 
    pathAnimation.duration = 0.01; 
    pathAnimation.fromValue = [NSNumber numberWithFloat:self.progress]; 
    pathAnimation.toValue = [NSNumber numberWithFloat:self.progress+0.01]; 
    [pathAnimation setDelegate:self]; 
    [self.pathLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; 

    [CATransaction begin]; 
    [CATransaction setDisableActions:YES]; 
    [self.pathLayer setStrokeEnd:self.progress + 0.01]; 
    [CATransaction commit]; 
} 

雖然,這也是值得注意的,你可以只通過只使用一個CATransaction,併爲strokeEnd隱式動畫製作動畫。

例如:

- (void)start { 

    [CATransaction begin]; 
    [CATransaction setAnimationDuration:0.01]; 
    [CATransaction setCompletionBlock:^{ 
     self.progress += 0.01; 

     if (self.progress < 1.0) { 
      [self start]; 
     } 
    }]; 
    [self.pathLayer setStrokeEnd:self.progress + 0.01]; 
    [CATransaction commit]; 
} 

這樣,你不必創建每個迭代一個新的明確的動畫。

+0

感謝您的幫助,我終於知道了〜 – melody5417