【问题标题】:Custom timer animation using UIBezierPath使用 UIBezierPath 自定义计时器动画
【发布时间】:2014-01-15 00:16:11
【问题描述】:

我目前有一个计时器,它在下面动画一条圆形线 - 一条倒计时线。这会根据我传递给 _percent 的秒数来制作动画。

我想要另一个描绘秒的圆形轮子。但是,我正在努力让动画在 _percent 中每一秒持续 1 秒。例如如果百分比是 100,我希望循环动画 100 次,持续 1 秒。 (以及实现下图的动画效果。

为了清楚起见,这里是一张图:) 第一行 3 显示了它现在的样子,最后一行 3 显示了我想要的效果......

这是我在视图控制器类中触发计时器的方法:

-(void)viewDidLoad
{
       CPCircleCountdownView *m_testView;
    m_testView.percent = 100;
}

- (IBAction)StartTimerButtonPressed:(id)sender
{
    // Kick off a timer to count it down
    m_timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(decrementSpin) userInfo:nil repeats:YES];
}

- (void)decrementSpin
{
    // If we can decrement our percentage, do so, and redraw the view
    if (m_testView.percent > 0) {
        m_testView.percent = m_testView.percent - 1;
        [m_testView setNeedsDisplay];
    }
    else {
        [m_timer invalidate];
        m_timer = nil;
    }
}

这是我的 CPCountdownView,我想在其中添加新的圆形动画,每剩下一秒钟持续一秒钟。理论上两个动画应该同时完成。

#import "CPCircleCountdownView.h"

@interface CPCircleCountdownView ()
{
    CGFloat startAngle;
    CGFloat endAngle;
}

@end

@implementation CPCircleCountdownView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code

        self.backgroundColor = [UIColor clearColor];

        //get start and end angles
        startAngle = M_PI * 1.5;
        endAngle = startAngle + (M_PI * 2);
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    //Display arc percent
    //NSString *textContent = [NSString stringWithFormat:@"%d", self.percent];    //TODO: Pass total number of seconds int

    //-------------------------
    UIBezierPath* bezierPath = [UIBezierPath bezierPath];
    // Create our arc, with the correct angles
    [bezierPath addArcWithCenter:CGPointMake(rect.size.width / 2, rect.size.height / 2)
                          radius:130
                      startAngle:startAngle
                        endAngle:(endAngle - startAngle) * (_percent / _overallScore) + startAngle
                       clockwise:YES];
    // Set the display for the path, and stroke it
    bezierPath.lineWidth = 2;
    [[UIColor colorWithRed:122.0 / 255.0 green:197.0 / 255.0 blue:205.0  / 255.0 alpha:1.0] setStroke];
    [bezierPath stroke];

    //-------------------------  
}

任何帮助都会很棒我相对较新,所以如果你能给我一些很好的例子:)谢谢

【问题讨论】:

    标签: ios objective-c nstimer countdown uibezierpath


    【解决方案1】:

    可能更好的方法是使用 2 个 CAShapeLayers 并为贝塞尔路径设置动画。假设 CPCircleCountdownView 是 UIView 子类

     @interface CPCircleCountdownView ()
    
      @property (nonatomic) CAShapeLayer* layer1;
      @property (nonatomic) CAShapeLayer* layer2;
      @property (nonatomic, assign) float startAngle;
      @property (nonatomic, assign) float endAngle;    
     @end   
    
     @implementation CPCircleCountdownView
    
     - (void)intiWithFrame:(CGRect) Frame
     {
       self = [super initWithFrame:frame];
       if (self) {
          _startAngle = M_PI * 1.5;
         _endAngle = _startAngle + (M_PI * 2);
    
        }
    
    
     }
    
    -(void)layoutSubviews{
    
        self.layer1 = [CAShapeLayer layer];
        self.layer1.fillColor = [UIColor clearColor].CGColor;
        self.layer1.strokeColor = [UIColor redColor].CGColor;
    
        self.layer2 = [CAShapeLayer layer];
        self.layer2.fillColor = [UIColor clearColor].CGColor;
        self.layer2.strokeColor = [UIColor greenColor].CGColor;
    
        [self.layer1 setFrame:CGRectMake(50, 50, 200, 200)];
        [self.layer2 setFrame:CGRectMake(50, 50, 200, 200)];
        UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.layer1.frame.size.width / 2, self.layer1.frame.size.height / 2)
                                                         radius:130
                                                     startAngle:self.startAngle
                                                       endAngle:self.endAngle
                                                      clockwise:YES];
    
        UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.layer2.frame.size.width / 2, self.layer2.frame.size.height / 2)
                                                         radius:125
                                                     startAngle:self.endAngle
                                                       endAngle:self.startAngle
                                                      clockwise:NO];
    
        self.layer1.path = path1.CGPath;
        self.layer2.path = path2.CGPath;
        [self.view.layer addSublayer:self.layer1];
        [self.view.layer addSublayer:self.layer2];
        [self.layer1  setStrokeEnd:1.0f];
        [self.layer2 setStrokeEnd:0.0f];
       // i've placed this here for convenience in testing, really it should be in method called by your button Action
        [self decrementSpinForValue:100];
    
    }
    
    - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished {
        [self.layer1 removeAllAnimations];
        [self.layer2 removeAllAnimations];
    }
    
    
    -(void) decrementSpinForValue:(float) percent{
    
        CABasicAnimation *strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        strokeEndAnimation.delegate = self;
        strokeEndAnimation.duration = percent;
        [strokeEndAnimation setFillMode:kCAFillModeForwards];
        strokeEndAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        strokeEndAnimation.removedOnCompletion = NO;
        strokeEndAnimation.fromValue = [NSNumber numberWithFloat:1.0f];
        strokeEndAnimation.toValue = [NSNumber numberWithFloat:0.0f];
        [self.layer1 addAnimation:strokeEndAnimation forKey:@"progressOuterStatus"];
    
        CABasicAnimation *strokeEndAnimation2 = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        strokeEndAnimation2.duration = 1.0f;
        strokeEndAnimation2.repeatCount = percent;
        [strokeEndAnimation2 setFillMode:kCAFillModeForwards];
        strokeEndAnimation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        strokeEndAnimation2.removedOnCompletion = NO;
        strokeEndAnimation2.fromValue = [NSNumber numberWithFloat:0.0f];
        strokeEndAnimation2.toValue = [NSNumber numberWithFloat:1.0f];
        [self.layer2 addAnimation:strokeEndAnimation2 forKey:@"progressInnerStatus"];
    
    
    }
    
    @end
    

    我认为这让您了解如何完成它。

    【讨论】:

    • 问题是当应用程序关闭并再次打开时,cabasicanimation被删除。意味着没有更多的动画。
    • 简单到可以添加通知并在上次停止的地方重新创建动画。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多