Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate CAShapeLayer with wave animation

Below i have attached image,I want to achieve the below animation.I have tried water wave animation but don't know how to control the animation like the above.

I have CAShapeLayer in which i have to achieve this animation.

enter image description here

Init Code

UIBezierPath *leftPath = [UIBezierPath bezierPath];
// Set the starting point of the shape.
[leftPath moveToPoint:CGPointMake(0,self.bounds.size.height/2)];
// Draw the lines.


[leftPath addLineToPoint:CGPointMake(0,self.bounds.size.height/2)];
[leftPath addLineToPoint:CGPointMake(self.bounds.size.width,self.bounds.size.height/2)];


leftLayer.path = leftPath.CGPath;
leftLayer.strokeColor = [[UIColor whiteColor] CGColor];
leftLayer.fillColor = nil;
leftLayer.borderWidth = 3.0f;
leftLayer.lineCap = kCALineCapRound;
leftLayer.lineJoin = kCALineJoinRound;

leftLayer.borderColor=[UIColor blackColor].CGColor;
[self.layer addSublayer:leftLayer];

Animation Code

-(void)animateCureve{

CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
pathAnimation.duration = 3.5;
pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pathAnimation.fromValue = (id)leftLayer.path;
pathAnimation.toValue = (id)[self wavePath].CGPath;
pathAnimation.removedOnCompletion=NO;
[leftLayer addAnimation:pathAnimation forKey:@"path"];
}

The Curve Path

- (UIBezierPath *)wavePath {
//set start and end accordingly

UIBezierPath *startPath = [UIBezierPath bezierPath];
[startPath moveToPoint:CGPointMake(0, self.bounds.size.height/2)];
[startPath addCurveToPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height/2) controlPoint1:CGPointMake(50, self.bounds.size.height/2+0)  controlPoint2:CGPointMake(self.bounds.size.width/2, 20) ];



return startPath;
}
like image 978
Mukesh Avatar asked Jul 20 '15 14:07

Mukesh


1 Answers

Taking a closer look at the frames, it looks like a shallow quadratic curve moving along the path. What you could try is define a range for the beginning and ending of the curve, say start and end, and then add the control point in the middle. Then just add the straight lines at both ends afterwards. Something I quickly wrote:

CGFloat start;
CGFloat end;
CGFloat heightOfQuad;
CGFloat mid = (start + end)/2;

UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(start, 0)];
[path addQuadCurveToPoint:CGPointMake(end, 0) controlPoint:CGPointMake(mid, heightOfQuad)];

UIBezierPath *startPath = [UIBezierPath bezierPath];
[startPath moveToPoint:CGPointMake(0, 0)];
[startPath addLineToPoint:CGPointMake(start, 0)];

UIBezierPath *endPath = [UIBezierPath bezierPath];
[endPath moveToPoint:CGPointMake(end, 0)];
[endPath addLineToPoint:CGPointMake(lengthOfViewHere, 0)];

[startPath appendPath:path];
[startPath appendPath:endPath];

*I haven't tested this out yet, but you can give it a go

UPDATE:

- (UIBezierPath *)wavePath {

    CGFloat mid = (self.start + self.end)/2;
    CGFloat y = self.frame.size.height;

    UIBezierPath *curvePath = [UIBezierPath bezierPath];
    [curvePath moveToPoint:CGPointMake(self.start, y)];
    [curvePath addQuadCurveToPoint:CGPointMake(self.end, y) controlPoint:CGPointMake(mid, y - waveHeight)];

    UIBezierPath *startPath = [UIBezierPath bezierPath];
    [startPath moveToPoint:CGPointMake(0, y)];
    [startPath addLineToPoint:CGPointMake(self.start, y)];

    UIBezierPath *endPath = [UIBezierPath bezierPath];
    [endPath moveToPoint:CGPointMake(self.end, y)];
    [endPath addLineToPoint:CGPointMake(self.frame.size.width, y)];

    [startPath appendPath:curvePath];
    [startPath appendPath:endPath];

    return startPath;
}
- (void)setWavePosition:(CGFloat)wavePosition {

    //from 0.0 to 1.0
    _wavePosition = wavePosition;

    //set start and end accordingly
    CGFloat waveCoordinate = wavePosition * self.frame.size.width;
    self.start = waveCoordinate - waveWidth/2;
    self.end = waveCoordinate + waveWidth/2;

    self.path = [self wavePath].CGPath;
    [self setNeedsDisplay];
}

After playing around some, the code above generates this with position at 0.5, waveHeight at 5.0, and waveWidth of 150.0 in a view width of 200.0: enter image description here

All you should need to do is set wavePosition, and then wavePath will give back the new path.

like image 174
David Cao Avatar answered Sep 28 '22 05:09

David Cao