使用UIBezierPath

时间:2017-05-06 06:20:14

标签: ios objective-c caanimation

问题:

如果您查看我当前的代码,如果targetSeconds高于~2-3秒,您会看到它正常工作。

但是,如果targetSeconds为0.005秒,它将无效,因为它无法在0.005秒内完成100次方法调用。因此,有没有人对我能做些什么改进呢?我宁愿不包括第三方GitHub存储库。

当前代码:

// Target seconds means the seconds that it'll take to become 100.0f.    
- (void)startAnimatingWithTargetSeconds:(NSTimeInterval)targetSeconds{
// Try to set timeInterval to 0.005f and you'll see that it won't finish in 0.005f
  [NSTimer scheduledTimerWithTimeInterval:targetSeconds / 100.0f target:self selector:@selector(animateWithTimer:) userInfo:nil repeats:YES];
}


- (void)animateWithTimer:(NSTimer *)timer {
  BOOL isFinished = self.currentProgress >= 100;

  if (isFinished) {
    // Invalidate timer
    if (timer.isValid) {
      [timer invalidate];
    }

    // Reset currentProgress
    self.currentProgress = 0.0f;
   }else{
     if (timer.isValid) {
        self.currentProgress += 1;
     }
  }
}

// Overriden setter
- (void)setCurrentProgress:(CGFloat)currentProgress {
  if (_currentProgress == currentProgress) {
    return;
  }

  dispatch_async(dispatch_get_main_queue(), ^{
    _currentProgress = currentProgress;
    [self setNeedsDisplay];
  });
}

然后在drawRect中,我有UIBezierPath基本上根据self.currentProgress绘制圆圈。

这样的事情:CGFloat endAngle = (self.currentProgress / 100.0f) * 2 * M_PI + startAngle;

问题:

在我的情况下,是否有任何公式或任何可以帮助我的方法?因为如果我将self.currentProgress设置为self.currentProgress += 5;而不是1,那么它的动画效果会更快,这正是我正在寻找的。

2 个答案:

答案 0 :(得分:1)

首先,你想什么时候每隔0.005秒重绘一次?那个200 FPS,比你需要的还要多。

不要重新发明轮子 - 利用核心动画! Core Animation已经知道如何以适当的速率调用状态更改函数,以及如何根据需要重绘视图,假设您告诉它该做什么。这个策略的要点如下:

  1. 向图层添加动态属性,表示饼图切片的完整性。
  2. 告诉核心动画,可以通过覆盖actionForKey:或将动画设置为actions字典(或更多选项,详细here)来动画此属性。
  3. 告诉核心动画,对此属性的更改需要使用needsDisplayForKey:重新绘制图层。
  4. 实施display方法,根据动态属性的表示层值重绘饼图。
  5. 完成!现在,您可以将动态属性从任何值设置为任何其他值,就像您的不透明度,位置等一样.Core Animation负责时间和回调,并且您可以获得平滑的60 FPS。

    对于某些示例,请参阅以下资源,按有用性降低的顺序列出(在我看来):

    祝你好运!

答案 1 :(得分:0)

我更喜欢使用这样的东西,因为小间隔的计时器(和睡眠)工作非常不准确:

-(void)startAnimatingWithTargetSeconds:(NSTimeInterval)targetSeconds
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        float fps = 60;
        float currentState = 0;
        float frameStateChange = fps/targetSeconds;
        NSDate *nextFrameDate = [NSDate date];
        while (currentState < 1) {
            currentState += frameStateChange;
            self.currentProgress = roundf(currentState * 100.);
            nextFrameDate = [nextFrameDate dateByAddingTimeInterval:1./fps];
            while ([nextFrameDate timeIntervalSinceNow] > 0) {
                usleep((useconds_t)(100000/fps));
            }
        }
        self.currentProgress = 0;
    });
}