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% のプログレス バーの画像:

プログレスバーが 0%

プログレスバーが 75%

助けてくれてありがとう。

4

2 に答える 2

0

アニメーション中に描画コードを複数回呼び出してはなりません。あなたの場合、最も簡単な方法は、開始状態用と最終状態用の 2 つのビューを使用することです。それらをサブビューとしてプログレス バー ビューに追加できます。次に、両方のビューを 1 回だけ描画し (または既製の画像を使用することもできます)、ビューのフレームをアニメーション化します。

例えば

...
[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;
    }];
}

また、グラデーションカラーでなくても、任意の 2 つの画像を使用できます。

于 2012-07-23T12:34:05.400 に答える
0

最終的には、クリップされた UIView をレイヤー化して animateWithDuration:animations を使用するという、はるかに単純なアプローチを採用しました。

ここにメインコードがあります -

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

}

かなり簡単で、うまく機能します。

于 2012-09-13T17:40:31.667 に答える