iPhone Quartz2D render expanding circle

2019-06-01 19:27发布

问题:

I'm curious as to the 'proper' method for achieving the following functionality using Quarts2D:

I want to have a view, and to be able to add a circle at any coordinate. As soon as I add the circle it should expand at a predefined rate; I'd also like to repeat this process and have a number if these expanding circles.

Think Missile Command:

Generally, if I was writing this in C++ using SDL or some other graphics library I would:

Have a class to represent an 'growing circle' Have a vector/array to hold pointers to all the 'growing circles' I create.

All circles diameters would be increased each tick, and in my renderloop I would iterate the list and draw appropriate circles to my buffer.

This, however, doesn't seem to fit well with how I've generally used views in previous iPhone development.

So I guess it's kind of open-ended, but is there a 'correct' way for something like this?

Would it be in a game loop style (as described above), or should I be subclassing UIView for a 'circle' object, and override drawRect? I guess I would then have to add each circle by creating a view and adding it to my main view?

Initial investigation also brought me across references to the CAShapeLayer class, though I'm guessing this might be much the same as implementing the UIView subclassing technique.

回答1:

Here's one way to do it. Add the following code to your UIViewController subclass and you'll get a circle that grows and then fades away wherever you touch:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self addGrowingCircleAtPoint:[[touches anyObject] locationInView:self.view]];
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    if (flag && [[anim valueForKey:@"name"] isEqual:@"grow"]) {
        // when the grow animation is complete, we fade the layer
        CALayer* lyr = [anim valueForKey:@"layer"];
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
        animation.fromValue = [lyr valueForKey:@"opacity"];
        animation.toValue = [NSNumber numberWithFloat:0.f];
        animation.duration = .5f;
        animation.delegate = self;
        lyr.opacity = 0.f;  
        [animation setValue:@"fade" forKey:@"name"];
        [animation setValue:lyr forKey:@"layer"];
        [lyr addAnimation:animation forKey:@"opacity"];
    } else if (flag && [[anim valueForKey:@"name"] isEqual:@"fade"]) {
        // when the fade animation is complete, we remove the layer
        CALayer* lyr = [anim valueForKey:@"layer"];
        [lyr removeFromSuperlayer];
        [lyr release];
    }

}

- (void)addGrowingCircleAtPoint:(CGPoint)point {
    // create a circle path
    CGMutablePathRef circlePath = CGPathCreateMutable();
    CGPathAddArc(circlePath, NULL, 0.f, 0.f, 20.f, 0.f, (float)2.f*M_PI, true);

    // create a shape layer
    CAShapeLayer* lyr = [[CAShapeLayer alloc] init];
    lyr.path = circlePath;

    // don't leak, please
    CGPathRelease(circlePath);
    lyr.delegate = self;

    // set up the attributes of the shape layer and add it to our view's layer
    lyr.fillColor = [[UIColor redColor] CGColor];
    lyr.position = point;
    lyr.anchorPoint = CGPointMake(.5f, .5f);
    [self.view.layer addSublayer:lyr];

    // set up the growing animation
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
    animation.fromValue = [lyr valueForKey:@"transform"];
    // this will actually grow the circle into an oval
    CATransform3D t = CATransform3DMakeScale(6.f, 4.f, 1.f);
    animation.toValue = [NSValue valueWithCATransform3D:t];
    animation.duration = 2.f;
    animation.delegate = self;
    lyr.transform = t;  
    [animation setValue:@"grow" forKey:@"name"];
    [animation setValue:lyr forKey:@"layer"];
    [lyr addAnimation:animation forKey:@"transform"];
}