Invert Core Animation Direction - cabasicanimation

How can i change the vertical Direction of an Animation?
Currently i have this:
-(void) flipAway{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform"];
self.view.layer.zPosition = 100;
CATransform3D transform = CATransform3DMakeRotation(M_PI, 1, 0, 0);
transform.m34 = 1.0/800.0;
[animation setToValue:[NSValue valueWithCATransform3D:transform]];
[animation setDuration:5];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
[animation setFillMode:kCAFillModeForwards];
[animation setRemovedOnCompletion:NO];
[animation setDelegate:self];
[self.view.layer addAnimation:animation forKey:#"test"];
}
And this works, BUT the rotation is a flip from top to bottom, how can i invert this to be from bottom to top?

Not sure what you're asking for.
CATransform3D transform = CATransform3DMakeRotation(- M_PI, 1, 0, 0);

The target was to invert Animation Direction : instead from bottom to top , i wanted to have it from top to bottom, i finally achieved this by adding an anchor Point for the animation:
CGRect frame = self.view.layer.frame;
CGPoint center = CGPointMake(CGRectGetMidX(frame), frame.size.height);
self.view.layer.position = center;
self.view.layer.anchorPoint = CGPointMake(0.5, 1);
I don't know why, but once you add this lines, the animation inverts..

Related

Change speed of "marching ants" effect after every 10 seconds

I'd like to change the Speed of my "Marching ants" effect after it has looped every 10 times. So it's looping the animation with a duration of 1, after the 10 loops it should change the duration to 0.95, after 10 more seconds to 0.9 and so on....
Do you have an idea how I could do this?
Here's the code for my current animation:
CAShapeLayer *lineLayer = [CAShapeLayer layer];
lineLayer.bounds = CGRectMake(0, 0, self.view.bounds.size.width, 20);
lineLayer.position = self.view.center;
lineLayer.strokeColor = [UIColor whiteColor].CGColor;
lineLayer.lineDashPattern = #[#100];
lineLayer.lineWidth = CGRectGetHeight(lineLayer.bounds);
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:CGPointMake(0, CGRectGetMidY(lineLayer.bounds))];
[linePath addLineToPoint:CGPointMake(CGRectGetMaxX(lineLayer.bounds), CGRectGetMidY(lineLayer.bounds))];
lineLayer.path = linePath.CGPath;
// [self.view.layer addSublayer:lineLayer];
NSNumber *totalDashLenght = [lineLayer.lineDashPattern valueForKeyPath:#"#sum.self"]; // KVC is awesome :)
CABasicAnimation *animatePhase = [CABasicAnimation animationWithKeyPath:#"lineDashPhase"];
animatePhase.byValue = totalDashLenght; // using byValue means that even if the layer has a shifted phase, it will shift on top of that.
animatePhase.duration = 0.5;
animatePhase.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animatePhase.repeatCount = 10;
// [lineLayer addAnimation:animatePhase forKey:#"marching ants"];
// Create the shape layer
shapeLayer = [CAShapeLayer layer];
CGRect shapeRect = CGRectMake(0.0f, 0.0f, 2200.0f, 2000.0f);
[shapeLayer setBounds:shapeRect];
[shapeLayer setPosition:CGPointMake(160.0f, 1350.0f)];
[shapeLayer setFillColor:[[UIColor clearColor] CGColor]];
[shapeLayer setStrokeColor:[[UIColor whiteColor] CGColor]];
[shapeLayer setLineWidth:20.0f];
[shapeLayer setLineJoin:kCALineJoinRound];
[shapeLayer setLineDashPattern:
[NSArray arrayWithObjects:[NSNumber numberWithInt:200],
[NSNumber numberWithInt:100],
nil]];
// Setup the path
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, shapeRect);
[shapeLayer setPath:path];
CGPathRelease(path);
// Set the layer's contents
//[shapeLayer setContents:(id)[[UIImage imageNamed:#"GEIST.jpg"] CGImage]];
[[[self view] layer] addSublayer:shapeLayer];
if ([shapeLayer animationForKey:#"linePhase"])
[shapeLayer removeAnimationForKey:#"linePhase"];
else {
CABasicAnimation *dashAnimation;
dashAnimation = [CABasicAnimation
animationWithKeyPath:#"lineDashPhase"];
[dashAnimation setFromValue:[NSNumber numberWithFloat:0.0f]];
[dashAnimation setToValue:[NSNumber numberWithFloat:300.0f]];
[dashAnimation setDuration:1];
[dashAnimation setRepeatCount:10];
[shapeLayer addAnimation:dashAnimation forKey:#"linePhase"];
Just set yourself up to detect the end of your animation, either with a delegate method or with a completion block on the transaction. When your animation completes its ten repetitions, you can schedule a new animation with a shorter duration.
(And remember being small, playing under the table and dreaming...)

CATransition animation zoom change image (UIImageView)

I try to achieve zooming animation image change on UIImageView.
So far I created a transition of type moveIn and subtype fromLeft:
CATransition *transition = [CATransition animation];
[transition setSubtype:kCATransitionFromLeft];
[transition setType:kCATransitionMoveIn];
[transition setDuration:1.5];
[[imageView layer] addAnimation:transition forKey:nil];
But I want a zooming effect. I successfully created it by using CABasicAnimation:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transition.scale"];
[animation setFromValue:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0, 0.0, 1.0)]];
[animation setToValue:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)]];
[animation setDuration:1.5];
[[imageView layer] addAnimation:animation forKey:nil];
My problem is that, using the second approach, the image changes (old image is gone) and then the animation comes in.
So it's an animation and not transition (as the names imply).
How can I create a transition with zoom effect?
Can use this to scale.
setTransform:CGAffineTransformMakeScale

how to put shake animation on uiimageview?

I've been trying to implement this but couldn't find any code that could shake it like iPhone app shakes while deleting them!
CABasicAnimation *animation =
[CABasicAnimation animationWithKeyPath:#"position"];
[animation setDuration:0.05];
[animation setRepeatCount:8];
[animation setAutoreverses:YES];
[animation setFromValue:[NSValue valueWithCGPoint:
CGPointMake([lockView center].x - 20.0f, [lockView center].y)]];
[animation setToValue:[NSValue valueWithCGPoint:
CGPointMake([lockView center].x + 20.0f, [lockView center].y)]];
[[lockView layer] addAnimation:animation forKey:#"position"];
you can achieve this by the following code, you have define the rotation angle from and to.
CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
[anim setToValue:[NSNumber numberWithFloat:0.0f]];
[anim setFromValue:[NSNumber numberWithDouble:M_PI/16]]; // rotation angle
[anim setDuration:0.1];
[anim setRepeatCount:NSUIntegerMax];
[anim setAutoreverses:YES];
[[imageView layer] addAnimation:anim forKey:#"iconShake"];
try this:
- (void)animateImage
{
CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:#"transform"];
CGFloat wobbleAngle = 0.06f;
NSValue* valLeft = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(wobbleAngle, 0.0f, 0.0f, 1.0f)];
NSValue* valRight = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(-wobbleAngle, 0.0f, 0.0f, 1.0f)];
animation.values = [NSArray arrayWithObjects:valLeft, valRight, nil];
animation.autoreverses = YES;
animation.duration = 0.125;
animation.repeatCount = HUGE_VALF;
[[lockView layer] addAnimation:animation forKey:#"shakeAnimation"];
}

Cocoa draw image with rounded corners and shadow

I am trying to draw an image using core graphics such that it has rounded corners and a drop shadow. Here is a snippet of my code:
CGContextSetShadowWithColor(context, CGSizeMake(0, 1), 2, shadowColor);
CGContextAddPath(context, path);
CGContextClip(context);
CGContextDrawImage(context, rect, image);
The problem I am having is that the clipping to create the rounded corners is also clipping the shadow. Since the image may be transparent in areas, I cannot simply draw the rounded rectangle with a shadow under the image. I guess I need to apply the rounded shape to the image first, and then draw the resulting image to the screen and add the shadow. Does anyone know how to do this?
Thanks!
Okay, so assuming that you have a UIView subclass, which has an instance variable, image, which is a UIImage, then you can do your drawRect: function like so...
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGRect _bounds = [self bounds];
CGColorRef aColor;
CGContextRef context = UIGraphicsGetCurrentContext();
// Create a path
CGRect insetRect = CGRectInset(_bounds, kBSImageButtonBorder, kBSImageButtonBorder);
CGRect offsetRect = insetRect; offsetRect.origin = CGPointZero;
UIGraphicsBeginImageContext(insetRect.size);
CGContextRef imgContext = UIGraphicsGetCurrentContext();
CGPathRef clippingPath = [UIBezierPath bezierPathWithRoundedRect:offsetRect cornerRadius:CORNER_RADIUS].CGPath;
CGContextAddPath(imgContext, clippingPath);
CGContextClip(imgContext);
// Draw the image
[image drawInRect:offsetRect];
// Get the image
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Setup the shadow
aColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.5f].CGColor;
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 2.0f), 2.0f, aColor);
// Draw the clipped image in the context
[img drawInRect:insetRect];
}
I'm a little new to Quartz programming myself, but that should give you your image, centered in the rectangle, minus a border, with a corner radius, and a 2.f point shadow 2.f points below it. Hope that helps.
Here is a function to round the corners of an image using Daniel Thorpe's answer, in case you came here, like me, just looking for a way to do this.
+ (UIImage *) roundCornersOfImage:(UIImage *)image toRadius:(float)radius {
// create image sized context
UIGraphicsBeginImageContext(image.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// add rounded rect clipping path to context using radius
CGRect imageBounds = CGRectMake(0, 0, image.size.width, image.size.height);
CGPathRef clippingPath = [UIBezierPath bezierPathWithRoundedRect:imageBounds cornerRadius:radius].CGPath;
CGContextAddPath(context, clippingPath);
CGContextClip(context);
// draw the image
[image drawInRect:imageBounds];
// get the image
UIImage *outImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outImage;
}
You can use an imageView with a layer, the layer has properties for setting shadows and borders, this is how:
self.imageView = [[NSImageView alloc] initWithFrame:NSMakeRect(0,0,60,60)];
self.imageView.image = [NSImage imageNamed:#"yourImageName"];
self.imageView.wantsLayer = YES;
self.imageView.layer.cornerRadius = 10;
//make the shadow and set it
NSShadow* shadow = [[NSShadow alloc] init];
shadow.shadowBlurRadius = 2;
shadow.shadowOffset = NSMakeSize(2, -2);
shadow.shadowColor = [NSColor blackColor];
self.imageView.shadow = shadow;
Hope this helps, this is also much faster to draw then using drawRect overrides

Core Animation 'flip' animation

I'm looking to use Core Animation to simulate a flip clock animation in a Mac application. Currently I have three CALayer's representing the top and bottom half of the digit, and a third used to represent the flip animation (a solution found in the follow article: Creating an iPad flip-clock with Core Animation.
The animation of the flip layer is broken into two stages: flipping from the top to the middle of the digit, and then from the middle to the bottom. To achieve this, I use a delegate function which is called whenever an animation ends:
- (void)animationDidStop:(CAAnimation *)oldAnimation finished:(BOOL)flag
{
int digitIndex = [[oldAnimation valueForKey:#"digit"] intValue];
int currentValue = [[oldAnimation valueForKey:#"value"] intValue];
NSMutableArray *digit = [digits objectAtIndex:digitIndex];
CALayer *flipLayer = [digit objectAtIndex:tickerFlip];
CALayer *bottomLayer = [digit objectAtIndex:tickerBottom];
if([[oldAnimation valueForKey:#"state"] isEqual:#"top"] && flag) {
NSLog(#"Top animation finished");
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
flipLayer.contents = [bottomImages objectAtIndex:currentValue];
flipLayer.anchorPoint = CGPointMake(0.0, 1.0);
flipLayer.hidden = NO;
[CATransaction commit];
CABasicAnimation *anim = [self generateAnimationForState:#"bottom"];
[anim setValue:[NSString stringWithFormat:#"%d", digitIndex] forKey:#"digit"];
[anim setValue:[NSString stringWithFormat:#"%d", currentValue] forKey:#"value"];
[flipLayer addAnimation:anim forKey:nil];
} else if([[oldAnimation valueForKey:#"state"] isEqual:#"bottom"] && flag) {
NSLog(#"Bottom animation finished");
// Hide our flip layer
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
bottomLayer.contents = [bottomImages objectAtIndex:currentValue];
flipLayer.hidden = YES;
flipLayer.anchorPoint = CGPointMake(0.0, 0.0);
[CATransaction commit];
}
}
This delegate function makes use of a helper function which generates the transform for the flip layer depending upon its state:
- (CABasicAnimation *)generateAnimationForState:(NSString *)state
{
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"transform"];
anim.duration = 0.15;
anim.repeatCount = 1;
// Check which animation we're doing
if([state isEqualToString:#"top"])
{
anim.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0.0f, 1, 0, 0)];
anim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI/2, 1, 0, 0)];
}
else
{
anim.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(-M_PI/2, 1, 0, 0)];
anim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0.0f, 1, 0, 0)];
}
anim.delegate = self;
anim.removedOnCompletion = NO;
// Set our animations state
[anim setValue:state forKey:#"state"];
return anim;
}
This solution works but causes some slight flickering when an animation is in progress. I believe this is due to the transform on my flip layer resetting between the 'top' and 'bottom' animations. It's important to note that after the first stage of the animation completes, I set the flip layers anchor point to the top of the image, ensuring the flip pivots correctly.
Currently I'm unsure if my animation has been setup optimally. I'm new to transformations and Core Animation in general. Can anyone point me in the right direction?
After
anim.removedOnCompletion = NO;
try inserting this code:
anim.fillMode = kCAFillModeForwards;
And let me know. Essentially the code snippet is supposed to prevent the 'reset' that is causing the flicker.

Resources