"Red alert" animation effect with Quartz 2D or CALayer animation? - ios

I am new to animations and I just can not find data on how to create an alert light (simple red alert light that flickers).
I know how to animate CALayer and the basics of Quartz 2D, I am just looking for a tutorial or direction on how to achieve back light effect?
Thanks
Shani

Very hacky code (works but try not using it in production):
self.uiView1.backgroundColor = [UIColor redColor];
CABasicAnimation* selectionAnimation1 = [CABasicAnimation
animationWithKeyPath:#"opacity"];
selectionAnimation1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
selectionAnimation1.fromValue = [NSNumber numberWithFloat:0.0];
selectionAnimation1.toValue = [NSNumber numberWithFloat:1.0];
selectionAnimation1.duration = 0.10;
selectionAnimation1.repeatCount = 20;
[self.uiView1.layer addAnimation:selectionAnimation1
forKey:#"opacity"];
self.uiView2.backgroundColor = [UIColor blackColor];
CABasicAnimation* selectionAnimation2 = [CABasicAnimation
animationWithKeyPath:#"opacity"];
selectionAnimation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
selectionAnimation2.fromValue = [NSNumber numberWithFloat:1.0];
selectionAnimation2.toValue = [NSNumber numberWithFloat:0.0];
selectionAnimation2.duration = 0.10;
selectionAnimation2.repeatCount = 20;
[self.uiView2.layer addAnimation:selectionAnimation2
forKey:#"opacity"];
uiView1 & uiView2 completely overlap each other. You can replace the two uiView's with two UIImageView's, with one having an image of light turned on (red) and one with light turned off (black/gray). In which case background color change will be redundant.

Related

CABasicAnimation of object around itself (360 degrees)

Here's my Animation code:
CABasicAnimation *fullRotation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
fullRotation.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
fullRotation.duration = 4;
fullRotation.repeatCount= 1000;
[[stick layer] addAnimation:fullRotation forKey:#"60"];
fullRotation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
I'm trying to rotate "stick" around itself , but it seems that it's rotating around another point , which is by default the origin. What can I do to make it accomplish a full 360 degrees rotation around itself? Thanks in advance.
If you want to change the anchor point of stick use:
stick.layer.anchorPoint = CGPointMake(1.0,1.0);
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CALayer_class/Introduction/Introduction.html#//apple_ref/occ/instp/CALayer/anchorPoint
The rotation code I use:
CABasicAnimation *rotateAnim = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
rotateAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
rotateAnim.fromValue = [NSNumber numberWithFloat:0];
rotateAnim.toValue = [NSNumber numberWithFloat:(360 * M_PI / 180.0f)];
rotateAnim.repeatCount = HUGE_VALF;
rotateAnim.duration = 2.5;
rotateAnim.removedOnCompletion = NO;
[view.layer addAnimation:rotateAnim forKey:#"rotationAnimation"];

CALayer explicit animation

Guys I'm trying to perform a CABasicAnimation (just for the test purposes) following the Apple's guide
There's a piece of code:
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeAnim.fromValue = [NSNumber numberWithFloat:1.0];
fadeAnim.toValue = [NSNumber numberWithFloat:0.0];
fadeAnim.duration = 5.0;
[theLayer addAnimation:fadeAnim forKey:#"opacity"];
// Change the actual data value in the layer to the final value.
theLayer.opacity = 0.0;
Which tells that I should actually change a property at the end. But it seems not working fine(it changes opacity immediately) - the duration is not 5 (I changed it to 5 for better visibility) so the animation is not CABasicAnimation but implicit.
It only works when I set theLayer.opacity = 0.0; BEFORE I add the animation to layer. Am I doing something wrong or it is a bug in docs?
P.S running the latest XCode, iOS 7.1 simulator.
Update the model layer before adding the animation.
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeAnim.fromValue = [NSNumber numberWithFloat:1.0];
fadeAnim.toValue = [NSNumber numberWithFloat:0.0];
fadeAnim.duration = 5.0;
// Change the actual data value in the layer to the final value.
theLayer.opacity = 0.0;
[theLayer addAnimation:fadeAnim forKey:#"opacity"];

Animate UISegmentedControl image

Im trying to animate an image in a UISegmentedControl. This is what I have come up with but it doesn't work.
The animation itself works fine if I switch imageView.layer to _segmentedControl.layer in the last line of code.
What am I missing?
UIImageView *imageView = [[UIImageView alloc] init];
imageView.image = [_segmentedControl imageForSegmentAtIndex:0];
CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
scale.duration = 0.25;
scale.repeatCount = 2;
scale.autoreverses = YES;
scale.fromValue = [NSNumber numberWithFloat:1.0];
scale.toValue = [NSNumber numberWithFloat:0.0];
[imageView.layer addAnimation:scale forKey:#"scale"];
For future reference I would like to share the solution I came up with. Instead of animating the image for the segment, which doesn't seem possible, you can at least animate the subview of the segmented control.
UIView *subView = [[_segmentedControl subviews] objectAtIndex:0];
CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
scale.duration = 0.25;
scale.repeatCount = 1;
scale.autoreverses = YES;
scale.fromValue = [NSNumber numberWithFloat:1.0];
scale.toValue = [NSNumber numberWithFloat:0.95];
[subView.layer addAnimation:scale forKey:#"scale"];
You use the collection UIView. UISegmentedControl can not animate

How do I make a layer maintain the final value of a CABasicAnimation

Consider the following animation:
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = 1.0;
pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
pathAnimation.removedOnCompletion = NO;
pathAnimation.delegate = self;
This will essentially animate the drawing of the layer from one end to the next. The problem is that once the animation completes, the strokeEnd property resets back to 0 (where it was initially set). How do I make the final value "stick"?
I have attempted to change this in the animationDidStop delegate method. This mostly works, but can cause a flash of strokeEnd at 0 briefly, even when put inside a CATransaction to disable animations. I have also played with the additive and cumulative properties to no avail. Any suggestions?
You simply set the strokeEnd property to its final value yourself! Like this:
// your current code (stripped of unnecessary stuff)
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = 1.0;
pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
// just add this to it:
theLayer.strokeEnd = 1;
// and now add the animation to theLayer
If strokeEnd were implicitly animatable (so that that line would itself cause animation) we would turn off implicit animation first:
[CATransaction setDisableActions:YES];
theLayer.strokeEnd = 1;
Note that your pathAnimation.removedOnCompletion = NO; is wrong, and so is the other answer's kCAFillModeForwards. Both are based on misunderstandings of how Core Animation works.

CAAnimationGroup reverts to original position on completion

In iOS I'm trying to create the effect of an icon shrinking in size, and flying across the screen in an arc while fading out, and then disappearing. I've achieved these 3 effects with an CAAnimationGroup, and it does what I want. The problem is when the animation ends, the view appears back at the original position, full size and full opacity. Can anyone see what I am doing wrong in the code below?
The animation should not revert to it's original position, but just disappear at the end.
UIBezierPath *movePath = [UIBezierPath bezierPath];
CGPoint libraryIconCenter = CGPointMake(610, 40);
CGPoint ctlPoint = CGPointMake(self.imgViewCropped.center.x, 22.0);
movePath moveToPoint:self.imgViewCropped.center];
[movePath addQuadCurveToPoint:libraryIconCenter
controlPoint:ctlPoint];
CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
moveAnim.path = movePath.CGPath;
moveAnim.removedOnCompletion = NO;
CABasicAnimation *scaleAnim = [CABasicAnimation animationWithKeyPath:#"transform"];
scaleAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
scaleAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 1.0)];
scaleAnim.removedOnCompletion = NO;
CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:#"alpha"];
opacityAnim.fromValue = [NSNumber numberWithFloat:1.0];
opacityAnim.toValue = [NSNumber numberWithFloat:0.0];
opacityAnim.removedOnCompletion = NO;
CAAnimationGroup *animGroup = [CAAnimationGroup animation];
animGroup.animations = [NSArray arrayWithObjects:moveAnim,scaleAnim,opacityAnim, nil];
animGroup.duration = 0.6;
animGroup.delegate = self;
animGroup.removedOnCompletion = NO;
[self.imgViewCropped.layer addAnimation:animGroup forKey:nil];
I believe you need to set the fillMode property of your animations to kCAFillModeForwards. That should freeze the animations at their end time. Another suggestion (and honestly, this is what I'd usually do) is just se the properties of the layer itself to their final position after you've set up the animation. That way when the animation is removed, the layer will still have the final properties as part of its model.
As an aside, the removedOnCompletion flag of animations contained within a CAAnimationGroup is ignored. You should probably just remove those assignments since they're misleading. Replace them with assignments to fillMode as specified above.

Resources