Создание анимированных кружков с помощью Core Graphics и Core Animations - PullRequest
2 голосов
/ 27 февраля 2012

Я пытаюсь некоторое время, но безуспешно. Я сделал некоторый круг с анимацией, которую я хочу. Он оживляет от радиуса 23 до радиуса 7.

Shema

Есть код, который работает нормально, но без прозрачного круга.

Мне нужна помощь, чтобы этот "прозрачный внутренний круг" работал во время анимации.

Некоторые CustomLayer :

@dynamic circleRadius; // Linked post tells us to let CA implement our accessors for us.
// Whether this is necessary or not is unclear to me and one 
// commenter on the linked post claims success only when using
// @synthesize for the animatable property.



+ (BOOL)needsDisplayForKey:(NSString*)key {
    // Let our layer know it has to redraw when circleRadius is changed
    if ([key isEqualToString:@"circleRadius"]) {
        return YES;
    } else {
        return [super needsDisplayForKey:key];
    }
}

- (void)drawInContext:(CGContextRef)ctx {

    // This call is probably unnecessary as super's implementation does nothing
    [super drawInContext:ctx];


    CGRect rect = CGContextGetClipBoundingBox(ctx);

    CGContextSetRGBFillColor(ctx, 1.000, 0.533, 0.000, 0.1);
    CGContextSetRGBStrokeColor(ctx, 1.000, 0.533, 0.000, 0.5);

    // Construct a CGMutablePath to draw the light blue circle
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddArc(path, NULL, rect.size.width / 2, 
                 rect.size.height / 2, 
                 self.circleRadius, 0, 2 * M_PI, NO);


    // Fill the circle
    CGContextAddPath(ctx, path);

    CGContextFillPath(ctx);

    // Stroke the circle's border
    CGContextAddPath(ctx, path);
    CGContextStrokePath(ctx);

    // Release the path
    CGPathRelease(path);

    CGContextStrokePath(ctx);

}

и анимационная часть где-то в му UIView

CustomLayer *customLayer = [[CustomLayer alloc] init];

    if ([customLayer respondsToSelector:@selector(setContentsScale:)])
    {
        [customLayer setContentsScale:[[UIScreen mainScreen] scale]];
    }

    // Make layer big enough for the initial radius
    // EDIT: You may want to shrink the layer when it reacehes it's final size
    [customLayer setFrame:CGRectMake(0, 0, 57, 52)];
    [self.layer addSublayer:customLayer];


    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"circleRadius"];
    animation.repeatCount = MAXFLOAT;
    // Zoom in, oscillate a couple times, zoom in further
    animation.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:23], 
                        [NSNumber numberWithFloat:22], 
                        [NSNumber numberWithFloat:20], 
                        [NSNumber numberWithFloat:18], 
                        [NSNumber numberWithFloat:15], 
                        [NSNumber numberWithFloat:13],
                        [NSNumber numberWithFloat:11],
                        [NSNumber numberWithFloat:9],
                        [NSNumber numberWithFloat:7], 
                        [NSNumber numberWithFloat:7],
                        [NSNumber numberWithFloat:7],
                        [NSNumber numberWithFloat:7],
                        nil];
    // We want the radii to be 20 in the end
    customLayer.circleRadius = 7;

    // Rather arbitrary values.  I thought the cubic pacing w/ a 2.5 second pacing
    // looked decent enough but you'd probably want to play with them to get a more
    // accurate imitation of the Maps app.  You could also define a keyTimes array for 
    // a more discrete control of the times per step.
    animation.duration = 1.5;
    animation.calculationMode = kCAAnimationCubicPaced;

    [customLayer addAnimation:animation forKey:nil];

1 Ответ

5 голосов
/ 27 февраля 2012

Для случая, когда вам нужен «пончик», вам нужно будет создать чертеж примерно так:

CGMutablePathRef path = CGPathCreateMutable();
CGPathAddArc(path, NULL, rect.size.width / 2, 
             rect.size.height / 2, 
             self.circleRadius, 0, 2 * M_PI, NO);
CGPathAddArc(path, NULL, rect.size.width / 2, 
             rect.size.height / 2, 
             self.circleRadius/2.0, 0, 2 * M_PI, NO);
CGContextAddPath(ctx, path);

CGContextSetRGBFillColor(ctx, 1.000, 0.533, 0.000, 0.1);
CGContextEOFillPath(ctx);  // Note - you want the even-odd fill rule to get the donut

CGPathRelease( path);

// now the outside stroke

CGContextBeginPath( ctx ); // removes previous path
path = CGPathCreateMutable();
CGPathAddArc(path, NULL, rect.size.width / 2, 
         rect.size.height / 2, 
         self.circleRadius, 0, 2 * M_PI, NO);

CGContextSetRGBStrokeColor(ctx, 1.000, 0.533, 0.000, 0.5);

CGContextAddPath(ctx, path);
CGContextStrokePath(ctx);

CGPathRelease( path)

Для случая, когда вы просто хотите обвести внешний путь, сделайте именно это. Не выполняйте заполнение пути.

...