3

I have been trying to learn more about using CAShapeLayer animating it using path. The first thing came to my mind was having the effect of a "compressed" tennis ball against the edge before it bounces off.

But rather than using the fillPath of the layer, I tried to set an image to this layer. So I created another CALayer, assigned to its contents property an image and animate the shape layer's path.

But the result is that instead of the image being completely wrapped within this path, which, as I hoped, would grow and shrink as the path is being animated, the image is being revealed and cover while the path is being animated.

I would like to be able to have this image completely wrapped by the path and as the path is being animated, regardless of shapes, the image is still wrapped within this path on the shape layer. Image distortion is not an issue here.

What I had in mind is, for example, having a tennis ball image that I downloaded, wrapping it in CAShapeLayer in a upside-down teardrop-like path (see picture: enter image description here) and animate from a smaller upside-down teardrop shape into a larger upside-down teardrop and eventually shows a circle (a tennis ball image).

Is it possible to achieve this using CAShapeLayer? Could you please give me a sample here? Thanks in advance.

Adding Code:

Hi, this is what I got so far (thanks to @lnafziger)

//Setting up layer
- (void)setupLayer
{
    self.caShapeLayer = [CAShapeLayer layer];<
    self.caLayer = (CALayer*) self.layer;

    self.caLayer.contents = (id)([UIImage imageNamed:"@yellowTennisBall.png"] CGImage]);
    self.caLayer.mask = self.caShapeLayer;
}  

//Animate the path of CAShapeLayer
- (void)bounce
{ 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
    animation.duration = 1.7;
    animation.repeatCount = HUGE_VAL;
    animation.timingFunction = [CAMediaTimingFunction  functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.fromValue = (__bridge id)[self defaultPath];
    animation.toValue = (__bridge id)[self compressedPath];
    animation.autoreverses = YES;
    [self.caShapeLayer addAnimation:animation forKey:@"animatePath"];
}

For the aforementioned effect and wrapping UIImage within the path, I have gotten nowhere with coding...

lnafziger
  • 25,760
  • 8
  • 60
  • 101
Unheilig
  • 16,196
  • 193
  • 68
  • 98
  • Setting the path layer as the image layer's `maskLayer` should do what you want. (You might want to use an additional path layer for the stroke effect). – omz Jun 14 '13 at 20:07
  • 1
    That's not easily possible with Core Animation. Deforming an image to an arbitrary path is a fairly complex thing to do and there are no public APIs that would help you there. – omz Jun 18 '13 at 18:29

1 Answers1

3

CAShapeLayer is good for masking, but your needs are more than just masking. You would need to deform the image what is not simple and may not be achievable by CAShapeLayers.

There are some options..

First (the hard one): Draw (via -(void)drawRect:(CGRect)rect ) your marker by code respectively to the black dot. And then animate the change via a simple CoreAnimation animation.

Second (the easy one): Create a Sequence of images and start the animation like this:

NSArray * imageArray  = [[NSArray alloc] initWithObjects:
                         [UIImage imageNamed:@"1.png"],
                         [UIImage imageNamed:@"2.png"],
                         [UIImage imageNamed:@"3.png"],
                         [UIImage imageNamed:@"4.png"],
                         [UIImage imageNamed:@"5.png"],
                         [UIImage imageNamed:@"6.png"],
                         [UIImage imageNamed:@"7.png"],
                         [UIImage imageNamed:@"8.png"],
                         [UIImage imageNamed:@"9.png"],
                         [UIImage imageNamed:@"10.png"],
                         [UIImage imageNamed:@"11.png"],
                         [UIImage imageNamed:@"12.png"],
                         nil];
UIImageView * theImageViewToAnimate = [[UIImageView alloc] initWithFrame:
                         CGRectMake(100, 125, 150, 130)];
theImageViewToAnimate.animationImages = imageArray;
theImageViewToAnimate.animationDuration = 1.1;
theImageViewToAnimate.animationRepeatCount=1;

[theImageViewToAnimate startAnimating];
lukaswelte
  • 2,951
  • 1
  • 23
  • 45
  • Drawing is a tough work here.. You would need to specify hard borders in the code and if the rect intersects the borders draw accordingly to them.. So more or less a fake physics simulation. I would rather use the image array or directly use a physic engine – lukaswelte Jun 21 '13 at 08:17