2012-07-23 120 views
1

我有一个进度条,我使用重复计时器进行动画制作。它工作正常,除了动画不像使用核心动画那样流畅。如果任何人有任何建议如何使用核心动画来实现它,我将不胜感激!对于简单的东西,我没有使用核心动画的问题,但动画渐变等,已经难倒我。如何动画渐变进度条

我的代码是在这里 - 进度条的

-(id)initWithWidth:(float)theWidth radius:(float)theRadius progress:(float)theProgress 
{ 
    self = [super initWithFrame:CGRectMake(0, 0, theWidth, theRadius * 2)]; 
    if (self) { 

     _progressBarWidth = theWidth; 
     _radius = theRadius; 
     _progress = (float)theProgress; 

     self.backgroundColor = [UIColor clearColor]; 

    } 
    return self; 
} 


-(void)setProgress:(float)theProgress 
{ 
    _progress = theProgress; 
    [self setNeedsDisplay]; 
} 


-(void)drawRect:(CGRect)rect 
{ 
    // gradient for blue background (pale blue -> dark blue) 

    float colours[] = {0.0, 135.0/255.0, 237.0/255.0, 1.0, 1.0/255.0, 24.0/255.0, 140.0/255.0, 1.0}; 

    CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB(); 
    size_t num_locations = 2; 
    CGFloat locations[2] = {0.0, 1.0}; 
    CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colours, locations, num_locations); 

    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGContextSaveGState(context); 

    CGContextMoveToPoint(context, _radius, 0.0); 
    CGContextAddArcToPoint(context, _progressBarWidth, 0.0, _progressBarWidth, _radius, _radius); 
    CGContextAddArcToPoint(context, _progressBarWidth, 2.0 * _radius, _progressBarWidth - _radius, 2.0 * _radius, _radius); 
    CGContextAddArcToPoint(context, 0.0, 2.0 * _radius, 0.0, _radius, _radius); 
    CGContextAddArcToPoint(context, 0.0, 0.0, _radius, 0.0, _radius); 

    CGContextClosePath(context); 
    CGContextClip(context); 

    CGPoint startPoint = CGPointMake(_progressBarWidth/2.0, 0.0); 
    CGPoint endPoint = CGPointMake(_progressBarWidth/2.0, 2.0 * _radius); 

    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); 

    CGGradientRelease(gradient); 
    CGColorSpaceRelease(baseSpace); 

    CGContextRestoreGState(context); 


    // gradient for progressed element (pale yellow -> dark yellow) 

    float colours2[] = {252.0/255.0, 224.0/255.0, 0.0, 1.0, 246.0/255.0, 191.0/255.0, 0.0, 1.0}; 

    baseSpace = CGColorSpaceCreateDeviceRGB(); 
    gradient = CGGradientCreateWithColorComponents(baseSpace, colours2, locations, num_locations); 

    context = UIGraphicsGetCurrentContext(); 
    CGContextSaveGState(context); 

    // this defines an overall clipping path for the yellow bar (it's got a square end which can protrude when it's near 100%) 
    CGContextMoveToPoint(context, _radius, kDefaultLineWidth); 
    CGContextAddArcToPoint(context, _progressBarWidth - kDefaultLineWidth, kDefaultLineWidth, _progressBarWidth - kDefaultLineWidth, _radius, _radius - kDefaultLineWidth); 
    CGContextAddArcToPoint(context, _progressBarWidth - kDefaultLineWidth, 2.0 * _radius - kDefaultLineWidth, _progressBarWidth - _radius, 2.0 * _radius - kDefaultLineWidth, _radius - kDefaultLineWidth); 
    CGContextAddArcToPoint(context, kDefaultLineWidth, 2.0 * _radius - kDefaultLineWidth, kDefaultLineWidth, _radius, _radius - kDefaultLineWidth); 
    CGContextAddArcToPoint(context, kDefaultLineWidth, kDefaultLineWidth, _radius, kDefaultLineWidth, _radius - kDefaultLineWidth); 

    CGContextClosePath(context); 
    CGContextClip(context); 

    // now draw the yellow bar 
    float progressWidth = _progress * _progressBarWidth; 

    CGContextMoveToPoint(context, progressWidth, kDefaultLineWidth); 
    CGContextAddArcToPoint(context, kDefaultLineWidth, kDefaultLineWidth, kDefaultLineWidth, _radius, _radius - kDefaultLineWidth); 
    CGContextAddArcToPoint(context, kDefaultLineWidth, 2.0 * _radius - kDefaultLineWidth, _radius, 2.0 * _radius - kDefaultLineWidth, _radius - kDefaultLineWidth); 
    CGContextAddLineToPoint(context, progressWidth, 2.0 * _radius - kDefaultLineWidth); 

    CGContextClosePath(context); 
    CGContextClip(context); 

    startPoint = CGPointMake(progressWidth/2.0, kDefaultLineWidth); 
    endPoint = CGPointMake(progressWidth/2.0, 2.0 * _radius - kDefaultLineWidth); 

    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); 

    CGGradientRelease(gradient); 
    CGColorSpaceRelease(baseSpace); 

    CGContextRestoreGState(context); 


    // draw the scale 

    CGContextSetLineWidth(context, 0.25f); 
    CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor); 

    float div = _progressBarWidth/10; 
    for (float i = 1; i < 10; i++) { 

     CGContextMoveToPoint(context, div * i, 0.25); 
     CGContextAddLineToPoint(context, div * i, _radius * 2.0 + 1.75); 

     CGContextDrawPath(context, kCGPathStroke); 

    } 

    CGContextSetStrokeColorWithColor(context, [UIColor darkGrayColor].CGColor); 

    for (float i = 1; i < 10; i++) { 

     CGContextMoveToPoint(context, div * i - 0.5, 0.25); 
     CGContextAddLineToPoint(context, div * i - 0.5, _radius * 2.0 + 1.75); 

     CGContextDrawPath(context, kCGPathStroke); 

    } 

} 

图像在0%& 75%:

Progress bar at 0%

Progress bar at 75%

感谢您的帮助。

+1

你看过[CAGradientLayer](https://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CAGradientLayer_class/Reference/Reference.html)吗?这是为动画梯度制作的 – 2012-07-23 12:00:14

回答

0

在动画过程中,您不能多次调用绘图代码。 在你的情况下,最简单的方法是使用两个视图:一个用于开始状态,另一个用于最终状态。 您可以将它们作为子视图添加到进度栏视图。 然后,您只绘制一次这两个视图(或者甚至使用现成的图像)​​并为视图的帧添加动画。

E.g.

... 
[self addSubview:endView]; 
[self addSubview:startView]; 
... 

-(void)animateProgressFrom:(float)fromValue to:(float)toValue 
{ 
    CGRect startRect = self.bounds; 
    startRect.size.width *= fromValue; 
    startView.frame = startRect; 
    [UIView animateWithDuration:duration animations:^{ 
     CGRect endRect = self.bounds; 
     endRect.size.width *= toValue; 
     startView.frame = endRect; 
    }]; 
} 

它可以是任何两个图像,没有必要的渐变色。

+0

谢谢,但不幸的是,由于图形相当复杂的布局并不那么简单,据我看我不能只是“拉伸”它或覆盖的进展和动画它增长(半圆形的边缘,与自己的渐变边界)。我会尝试发布几张图片。 – SomaMan 2012-07-23 13:41:52

+0

我在原始问题结尾处链接了2张图片。 – SomaMan 2012-07-23 14:05:23

+0

我在上面的回答中描述的方法适用于您的图像。可以使用半圆形渐变和渐变边框。 它只适用于半透明图像。 – Vladimir 2012-07-26 15:22:09

0

我到底采用了更简单的方法,分层修剪UIViews &使用animateWithDuration:动画:

这里的主要代码 -

-(id)initWithWidth:(float)theWidth radius:(float)theRadius progress:(float)theProgress duration:(float)theDuration 
{ 
    self = [super initWithFrame:CGRectMake(0, 0, theWidth, theRadius * 2)]; 
    if (self) { 

     _progressBarWidth = theWidth; 
     _radius = theRadius; 
     _progress = (float)theProgress; 
     _animationDuration = theDuration; 

     self.backgroundColor = [UIColor clearColor]; 

     // make the view the right shape 

     self.layer.cornerRadius = _radius; 
     self.clipsToBounds = YES; 

    } 
    return self; 
} 


-(void)showProgress 
{ 

    // draw the main background (which is seen as the outline) 

    float tempColours[] = {0.0, 135.0/255.0, 237.0/255.0, 1.0, 1.0/255.0, 24.0/255.0, 140.0/255.0, 1.0}; 
    NSMutableArray *colours = [NSMutableArray array]; 
    for (int i = 0; i < 8; i++) { 
     [colours addObject:[NSNumber numberWithFloat:tempColours[i]]]; 
    } 

    // GradientView is a class which gives me UIViews with a gradient fill 

    GradientView *mainBGView = [[[GradientView alloc] initWithWidth:_progressBarWidth height:2.0 * _radius colours:colours] autorelease]; 
    mainBGView.frame = CGRectMake(0, 0, _progressBarWidth, 2.0 * _radius); 
    [self addSubview:mainBGView]; 


    // add the sub-background and progress bar element 

    UIView *clippingContainerView = [[[UIView alloc] initWithFrame:CGRectMake(kDefaultLineWidth, kDefaultLineWidth, _progressBarWidth - 2.0 * kDefaultLineWidth, 2.0 * _radius - 2.0 * kDefaultLineWidth)] autorelease]; 
    clippingContainerView.backgroundColor = [UIColor clearColor]; 
    clippingContainerView.layer.cornerRadius = _radius - kDefaultLineWidth; 
    clippingContainerView.clipsToBounds = YES; 

    float tempBackgroundColours[] = {152.0/255.0, 152.0/255.0, 152.0/255.0, 1.0, 216.0/255.0, 216.0/255.0, 216.0/255.0, 1.0}; 
    NSMutableArray *backgroundColours = [NSMutableArray array]; 
    for (int i = 0; i < 8; i++) { 
     [backgroundColours addObject:[NSNumber numberWithFloat:tempBackgroundColours[i]]]; 
    } 

    GradientView *greyBGView = [[[GradientView alloc] initWithWidth:_progressBarWidth - 2.0 * kDefaultLineWidth height:2.0 * _radius - 2.0 * kDefaultLineWidth colours:backgroundColours] autorelease]; 
    greyBGView.frame = CGRectMake(0, 0, _progressBarWidth - 2.0 * kDefaultLineWidth, 2.0 * _radius - 2.0 * kDefaultLineWidth); 
    [clippingContainerView addSubview:greyBGView]; 

    float tempProgressBarColours[] = {251.0/255.0, 215.0/255.0, 17.0/255.0, 1.0, 244.0/255.0, 184.0/255.0, 2.0/255.0, 1.0}; 
    NSMutableArray *progressBarColours = [NSMutableArray array]; 
    for (int i = 0; i < 8; i++) { 
     [progressBarColours addObject:[NSNumber numberWithFloat:tempProgressBarColours[i]]]; 
    } 

    GradientView *barGradientView = [[[GradientView alloc] initWithWidth:1.0 height:2.0 * _radius - 2.0 * kDefaultLineWidth colours:progressBarColours] autorelease]; 
    barGradientView.frame = CGRectMake(0, 0, 1, 2.0 * _radius); // start with progress bar too narrow to see 
    [clippingContainerView addSubview:barGradientView]; 

    [self addSubview:clippingContainerView]; 


    // animate the progress bar 

    float progressWidth = _progress * _progressBarWidth; // how wide it is at end of animation 
    [UIView animateWithDuration:_animationDuration 
        animations:^{ 
         barGradientView.frame = CGRectMake(0, 0, progressWidth, 2.0 * _radius); 
        }]; 

} 

相当直接的,&很好地完成这项工作。