开发者

Animate CALayer scale without blurring

I have a CALayer that implements drawInContext: and draws a simple circle, like so:

- (void)drawInContext:(CGContextRef)ctx
{
     CGContextScaleCTM(ctx, DrawingScale, DrawingScale);
     CGContextSetRGBFillColor (ctx, 1, 0, 0, 1);
开发者_JAVA技巧     CGContextFillEllipseInRect (ctx, LocationRectangle);
}

I have been experimenting with different ways of increasing the size of my circle based on a touch event. I've tried using the UIView beginAnimation system and CABasicAnimation's, bbut they all blur the image. In my reading I have discovered that is because the CALayer's seem to be treated like bitmaps for these options.

Fair enough... but I want to scale my graphics without blurring, e.g. to use vector scaling.

As such, in my code I have a "DrawingScale" property.

Is there a neat way to scale this property using Layer animations? Or is this something people do with NSTimers (yuk)?

Might this be one situation where I can use Core Animation's ability to animate custom properties? If so, I'd love to know which example people find is the best, or which section of the Apple docs might be a good place to start with this topic.

It seems when it comes to graphics on Mac/iOS, there are many ways to skin/draw a cat...?


After spending a few days working on this, one solution I have is to have a variable called "DrawingScale" as a member variable (is that what they are called in Obj-C) and using Core Animation to animate that property.

- (void)drawInContext:(CGContextRef)ctx
{
    CGFloat size = (CGFloat)(DrawingScale*DEFAULT_SIZE);
    CGRect elipseRect = CGRectMake(xPos, yPos, size, size);
    CGContextStrokeEllipseInRect(ctx, elipseRect);
    CGContextFillEllipseInRect (ctx, elipseRect);
}

Then on an event, I set up an animation as such:

-(void) : (CGPoint) location
{
    /* Set up an explicit animation to scale the players size up */
    CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"DrawingScale"];
    anim.fromValue = [NSNumber numberWithFloat: 1];
    anim.toValue = [NSNumber numberWithFloat: 5];
    anim.removedOnCompletion = YES;
    anim.duration = 0.1;
    anim.delegate = self;
    anim.fillMode = kCAFillModeForwards;
    anim.autoreverses = NO;
    [self addAnimation: anim forKey:@"ElipseGettingBigger"];
}

This sets up the animation to set my variable DrawingScale to range from 1 to 5, and do so within 0.1 of a second. It works really well.

I did need to be careful and make sure I had adjusted the layer bounds accordingly first too!


Use a shape layer (CAShapeLayer). You pass it a path, fill color, and stroke color and it will keep all of your edges crisp no matter the scale. If all you need is a circle though, you could just cheat and create a layer whose corner radius is half the width and height (assuming perfect square/circle). Something like:

CALayer *layer = [CALayer layer];
[layer setMasksToBounds:YES];
[layer setBackgroundColor[[UIColor redColor] CGColor]];
[layer setCornerRadius:25.0f];
[layer setBounds:CGRectMake(0.0f, 0.0f, 50.0f, 50.0f)];
[layer setPosition:CGPointMake([view bounds].size.width/2.0f, 
                               [view bounds].size.height/2.0f]);

[[view layer] addSublayer:layer];

You might also want to take a look at the latest WWDC videos from Apple. There are three sessions in there on Core Animation. The discuss layer scaling and keeping the edges crisp. The videos are free.

Best regards.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜