there are a lot of examples how to animate along a UIBezierPath. But i can't figure it out, how to animate only the appendPath of an UIBezierPath.
In my case i have the following example:
// Create path from view controller
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:
CGRectMake(0, 0, tutorialController.bounds.size.width,
tutorialController.bounds.size.height) cornerRadius:0];
// Create circle path
UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(x, y, 2.0*radius, 2.0*radius) cornerRadius:radius];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];
// Create spot layer
spotLayer = [CAShapeLayer layer];
spotLayer.path = path.CGPath;
spotLayer.fillRule = kCAFillRuleEvenOdd;
spotLayer.fillColor = [UIColor blackColor].CGColor;
spotLayer.opacity = 0.90;
So basically its a circle inside a rect and i now want to animate only the circle. In all attempts the rect was also moved.
Here is my example, how i can animate "along" a path
CGPoint pathStart = CGPointMake(96.000000, 226.000000);
CGPoint pathEnd = CGPointMake(120.000000, 300.000000);
[circlePath moveToPoint:pathStart];
[circlePath addLineToPoint:pathEnd];
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
anim.path = circlePath.CGPath;
anim.duration = 5.0;
anim.calculationMode = kCAAnimationPaced;
[spotLayer addAnimation:anim forKey:#"bezierPathAnim"];
But that is not what i want...
What i want to do is, to move my circle path (which is an appended path of a rectangle path) via animation
Does anybody has some ideas?
Regards
I solved my Problem :-)
Here is the solution...
// If there is an old path animate to the new path
if(oldPath != nil){
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"path"];
[anim setFromValue:(__bridge id)oldPath];
[anim setToValue:(__bridge id)[path CGPath]];
[anim setDuration:0.3];
[anim setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[spotLayer addAnimation:anim forKey:#"path"];
}
First of all i kept the oldPath (starting point) and then animate to the new setted path.
Related
I want to use a mask to achieve the effect that the visible part of the View changes as the mask is moved.
and this is my demo codeļ¼
- (void)drawLayer{
CAShapeLayer *maskLayer = [CAShapeLayer layer];
self.maskLayer = maskLayer;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.underView.bounds];
CGRect frame = CGRectMake(-4, -5, (self.underView.frame.size.width+8) *0.5, self.underView.frame.size.height+10);
UIBezierPath *topPath = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:frame.size.height *0.5];
NSLog(#"maskLayerframe:%#",NSStringFromCGRect(frame));
[path appendPath:topPath];
maskLayer.path = path.CGPath;
maskLayer.fillRule = kCAFillRuleEvenOdd;
self.underView.layer.mask = maskLayer;
}
///animation
/// - Parameter swipeToRight: Whether to slide to the right
- (void)startAnimation:(BOOL)swipeToRight{
CGFloat x = swipeToRight? self.underView.bounds.size.width *0.5-4:-4;
CGRect frame = CGRectMake(x, -5, (self.underView.frame.size.width+8) *0.5, self.underView.frame.size.height+10);
CAShapeLayer *maskLayer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.underView.bounds];
UIBezierPath *topPath = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:frame.size.height *0.5];
[path appendPath:topPath];
maskLayer.path = path.CGPath;
maskLayer.fillRule = kCAFillRuleEvenOdd;
[CATransaction begin];
[CATransaction setDisableActions:NO];
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[CATransaction setAnimationDuration:0.5];
self.maskLayer.frame = frame;
[CATransaction commit];
}
But the final animation looks like this, I don't know what's wrong with it, can anyone tell me please?
before animation
animation to right
animation back to left
I found right way to implementation it~
- (void)startAnimation:(BOOL)swipeToRight{
CGFloat x = swipeToRight? self.underView.bounds.size.width *0.5-4:-4;
CGRect frame = CGRectMake(x, -4, (self.underView.frame.size.width+8) *0.5, self.underView.frame.size.height+8);
CAShapeLayer *maskLayer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.underView.bounds];
UIBezierPath *topPath = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:frame.size.height *0.5];
[path appendPath:topPath];
maskLayer.path = path.CGPath;
maskLayer.fillRule = kCAFillRuleEvenOdd;
CABasicAnimation * basicAni = [CABasicAnimation animationWithKeyPath:#"path"];
basicAni.fromValue = (__bridge id _Nullable)(self.maskLayer.path);
basicAni.toValue = (__bridge id _Nullable)(maskLayer.path);
basicAni.duration = 0.4;
basicAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.underView.layer.mask addAnimation:basicAni forKey:#"path"];
[CATransaction begin];
[CATransaction setDisableActions:true];
self.maskLayer.path = maskLayer.path;
[CATransaction commit];
}
I am using below code to draw a Pie slice layer with CAShapeLayer.
CGFloat endAngle = (M_PI*2/5)-M_PI_2;
CAShapeLayer *outerBorderCircle = [CAShapeLayer layer];
int outerradius = self.frame.size.width/2;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(outerradius, outerradius)];
[path addLineToPoint:CGPointMake(outerradius, self.outerCircleBorder)];
[path addArcWithCenter:CGPointMake(outerradius,outerradius) radius:outerradius-self.outerCircleBorder startAngle:-M_PI_2 endAngle:endAngle clockwise:YES];
[path closePath];
outerBorderCircle.path = path.CGPath;
outerBorderCircle.fillColor = [UIColor whiteColor].CGColor;
outerBorderCircle.strokeColor = self.borderShadowColor.CGColor;
outerBorderCircle.lineWidth = self.outerCircleBorder;
outerBorderCircle.lineJoin = kCALineJoinRound;
outerBorderCircle.zPosition = MAXFLOAT;
CABasicAnimation *startanimation = [CABasicAnimation animationWithKeyPath:#"fillColor"];
startanimation.removedOnCompletion = YES;
startanimation.fromValue = (id)[[UIColor clearColor] CGColor];
startanimation.toValue = (id)[[UIColor whiteColor] CGColor];
startanimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
startanimation.duration = 10.0;
[startanimation setFillMode:kCAFillModeBoth];
[outerBorderCircle addAnimation:startanimation forKey:#"fillColor"];
[self.layer addSublayer:outerBorderCircle];
But animation part working as fade in fade out. But i need to animate arc kind of animation.
Please help me.
To animate the stroke you should animate those properties:
-strokeStart
-strokeEnd
From the documentation:
Combined with the strokeEnd property, this property defines the
subregion of the path to stroke. The value in this property indicates
the relative point along the path at which to begin stroking while the
strokeEnd property defines the end point. A value of 0.0 represents
the beginning of the path while a value of 1.0 represents the end of
the path. Values in between are interpreted linearly along the path
length.
[UPDATE]
CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
drawAnimation.duration = timeInSeconds;
drawAnimation.fromValue = [NSNumber numberWithFloat:startAngle];
drawAnimation.toValue = [NSNumber numberWithFloat:endAngle];
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[circle addAnimation:drawAnimation forKey:#"drawCircleAnimation"];
Credits to Rob Mayoff
I'm trying to animate a chart so it scales from the center. Now it scales from left to right.
Initial State:
Final State:
Animation:
Here is my code:
maskLayer = [[CAShapeLayer alloc] init];
maskLayer.borderColor=[UIColor redColor].CGColor;
maskLayer.borderWidth=1;
maskLayer.fillColor=UIColorFromRGB(0x91E5FF).CGColor;
maskLayer.frame = CGRectMake(0,0, rect.size.width, rect.size.height);
maskLayer.path = finalPath.CGPath;
maskLayer.opacity=0.8;
[self.layer addSublayer:maskLayer];
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"path"];
anim.duration = 4;
anim.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
anim.removedOnCompletion = NO;
anim.fillMode = kCAFillModeBoth;
anim.fromValue = (id)[initialPath CGPath];
anim.toValue= (id)[finalPath CGPath];
[maskLayer addAnimation:anim forKey:nil];
To get the results you want, you can't just scale - you'll have the same path at the start and finish. Your stated example has a path animation.
All you have to do is draw your paths in relation to each other, the way you want them to animate. If you want to animate your path as if it's anchored in the center, you need to draw them like that. Center both your paths on each other.
Here's a simple example:
UIBezierPath* initialPath = [UIBezierPath bezierPathWithRect: CGRectMake(-25, -25, 50, 50)];
UIBezierPath* finalPath = [UIBezierPath bezierPathWithRect: CGRectMake(-40, -40, 80, 80)];
In this example, your square will scale up from the center. If your path is currently scaling from the right, it's because thats where your paths are aligned.
I have an abstract strange shaped UIView.
And I need to display a smooth appearance animation.
I assume I should apply that animation to the mask above that view.
The mask is going to be circle shaped.
So user will see the 1'2'3'4' sequence.
How can I implement that?
I suppose I should apply some affine transformation
to the mask view. In that case, what should be the original shape of the mask?
A vertical line?
A simple example,suppose I have a 100*100 imageview,
Note:to make it simple,I use hard code numbers
CAShapeLayer * maskLayer = [CAShapeLayer layer];
maskLayer.bounds = CGRectMake(0, 0, 100, 100);
maskLayer.position = CGPointMake(50, 50);
UIBezierPath * path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50.0, 50.0) radius:50 startAngle:0 endAngle:M_PI *2 clockwise:true];
maskLayer.path = path.CGPath;
maskLayer.fillColor = [UIColor clearColor].CGColor;
maskLayer.strokeColor = [UIColor blackColor].CGColor;
maskLayer.strokeEnd = 0.0;
maskLayer.lineWidth = 100;
self.imageview.layer.mask = maskLayer;
CABasicAnimation * animation = [CABasicAnimation animation];
animation.keyPath = #"strokeEnd";
animation.toValue = #(1.0);
animation.duration = 2.0;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
[maskLayer addAnimation:animation forKey:#"keyFrame"];
I need to drag UIView along bezier path from one point to another, What is the best way?
This is the easiest way to do drag a uiview from one point to another point.
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:startingPoint];
[path addLineToPoint:endPoint]; //you can use addCurveToPoint: , addArcToPoint:, etc
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.duration = 10.0;
pathAnimation.path = path;
pathAnimation.removeOnCompletion = NO ;
[myView.layer addAnimation:pathAnimation forKey:#"pathAnimation"];