Animate UISegmentedControl image - ios

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

Related

Animation resets to begin state after ending or firing second animation

I'm trying to make a breathing circle animation. Only breathInAnimation (grow circle) seems to animate. breathOutAnimation (shrink circle) gets called but doesn't seem to do anything. I'm guessing it immediately reverts back to the starting state but I don't understand why.
- (void)viewDidLoad
animationView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width / 2.0, self.view.frame.size.height / 2.0, 200, 200)];
animationView.backgroundColor = [UIColor blueColor];
animationView.layer.cornerRadius = 100;
animationView.center = self.view.center;
[self.view addSubview: animationView];
[self drawCircleEdge];
[self breathInAnimation];
[NSTimer timerWithTimeInterval:7.0 target:self selector:#selector(breathOutAnimation) userInfo:nil repeats:YES];
- (void)breathInAnimation
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
[scaleAnimation setValue:#"breathIn" forKey:#"id"];
scaleAnimation.duration = 4;
scaleAnimation.fromValue = [NSNumber numberWithFloat:0.1];
scaleAnimation.toValue = [NSNumber numberWithFloat:1];
[animationView.layer addAnimation:scaleAnimation forKey:#"scale"];
- (void)breathOutAnimation
CABasicAnimation *breathOut = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
breathOut.duration = 8;
breathOut.fromValue = [NSNumber numberWithFloat:1];
breathOut.toValue = [NSNumber numberWithFloat:0.1];
[animationView.layer removeAllAnimations];
[animationView.layer addAnimation: breathOut forKey:#"scale"];
I also tried using the delegate of scaleAnimation.
- (void)animationDidStop:(CABasicAnimation *)theAnimation2 finished:(BOOL)flag
This works but after the animation finished the circle goes back to the state it was after ending the first animation. Shrinking -> animation ends -> fullsize again.
I'm not sure what I'm missing here.
CAAnimations doesn't apply the transformation to your layer, it's animating on a presentation layer and then switch back to your layer when animation is finished.
You should apply your transform when you are playing the animation.
-(void)breathOutAnimation
{
CABasicAnimation *breathOut = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
breathOut.duration = 8;
breathOut.fromValue = [NSNumber numberWithFloat:1];
breathOut.toValue = [NSNumber numberWithFloat:0.1];
[animationView.layer removeAllAnimations];
[animationView.layer addAnimation: breathOut forKey:#"scale"];
animationView.layer.transform = CATransform3DMakeScale(0.1, 0.1, 0.1);
}

UIButton rotate with CABasicAnimation does not move initial touch coordinates

I have a UIView and i added a UIButton on it. I am rotating UIView by 180 degrees. After rotating UIView, everything inside it looks rotated including the button. But when i tap on button. it receives touch event only from its initial position. Not from the position it appears on screen. This is my code -
CABasicAnimation *fullRotation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
fullRotation.fromValue = [NSNumber numberWithFloat:0];
fullRotation.toValue = [NSNumber numberWithFloat:((180*M_PI)/180)];
fullRotation.speed = 1.0;
fullRotation.autoreverses = NO;
fullRotation.removedOnCompletion = NO;
fullRotation.fillMode = kCAFillModeForwards;
[_subView.layer addAnimation:fullRotation forKey:#"360"];
You can't do it from Interface Builder. You have to rotate it from your code. Like this,
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 200)];
[button addTarget:self action:#selector(selectedButton) forControlEvents:UIControlEventTouchUpInside];
[button setBackgroundColor:[UIColor purpleColor]];
CABasicAnimation *fullRotation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
fullRotation.fromValue = [NSNumber numberWithFloat:0];
fullRotation.toValue = [NSNumber numberWithFloat:((180*M_PI)/180)];
fullRotation.speed = 1.0;
fullRotation.autoreverses = NO;
fullRotation.removedOnCompletion = NO;
fullRotation.fillMode = kCAFillModeForwards;
[button.layer addAnimation:fullRotation forKey:#"360"];
[self.view addSubview:button];
Now the selectedButton will receive every rotated UIButton touch.

How to animate when switching CALayers

I'm adding and removing CALayers using this method :
[[[self.view.layer sublayers] objectAtIndex:0] removeFromSuperlayer];
if(++self.backgroundIndex > self.gradients.count - 1) {
self.backgroundIndex = 0;
}
CAGradientLayer *layer = [self.gradients objectAtIndex:self.backgroundIndex];
layer.frame = self.view.frame;
[self.view.layer insertSublayer:layer atIndex:0];
How can I animate this ? Thanks.
You can use Core Animation when adding and removing CALayers something like this
CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeOut.fromValue = [NSNumber numberWithFloat:1.0];
fadeOut.toValue = [NSNumber numberWithFloat:0.0];
fadeOut.duration = 1.0; // 1 second
[[[self.view.layer sublayers] objectAtIndex:0] addAnimation:fadeOut forKey:#"fadeOutAnimation"];
//Adding Layer animation
CAGradientLayer *layer = [self.gradients objectAtIndex:self.backgroundIndex];
CABasicAnimation *fadeIn = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeIn.fromValue = [NSNumber numberWithFloat:1.0];
fadeIn.toValue = [NSNumber numberWithFloat:0.0];
fadeIn.duration = 1.0; // 1 second
[layer addAnimation:fadeIn forKey:#"fadeInAnimation"];

Animating UIView shape and its content

In an iPhone app how would you animate the shape of an UIView, for example changing from a rectangle into a circle?
I've tried with:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"path"];
animation.duration = 20.0;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.fromValue = (__bridge_transfer id)aPath;
animation.toValue = (__bridge_transfer id)anotherPath;
[myShapeLayer addAnimation:animation forKey:#"animatePath"];
where myShapeLayer is an instance of CAShapeLayer and aPath and anotherPath CGMutablePathRef.
It works but the view content is not animated as well.
I need to transform a view into a circle and then let it shrink until it disappears.
Try something like this:
Where animeView is your UIView
CABasicAnimation *anim1 = [CABasicAnimation animationWithKeyPath:#"cornerRadius"];
anim1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
anim1.fromValue = [NSNumber numberWithFloat:0.0f];
anim1.toValue = [NSNumber numberWithFloat:50.0f]; //Half the size of your UIView
anim1.duration = 2.0;
[animeView.layer addAnimation:anim1 forKey:#"cornerRadius"];
[UIView animateWithDuration:10.0 delay:2 options:UIViewAnimationOptionCurveEaseInOut animations:^{
animeView.layer.cornerRadius = 50; //Half the size of your UIView
CGRect reduceRect = animeView.frame;
reduceRect.size.height = 0;
reduceRect.size.width = 0;
[animeView setFrame:reduceRect];
animeView.alpha = 0;
} completion:nil];
Might need some tweaks for you here and there ;-)
EDIT 1:
Ok so how about using two UIView animations?
The first will shrink, strech and move your view.
The second will shrink, slink and remove your view.
[UIView animateWithDuration:2.0 delay:0.5 options:UIViewAnimationOptionCurveEaseIn animations:^{
CGRect moveRect = animeView.frame;
moveRect.origin.x = 0;
moveRect.origin.y = (animeView.center.y -20); //Half the size of height reduction
moveRect.size.height = (animeView.bounds.size.height -40); // height reduction
moveRect.size.width = (animeView.bounds.size.width +20);
[animeView setFrame:moveRect];
} completion:^(BOOL finished){
[UIView animateWithDuration:2.0 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
CGRect reduceRect = animeView.frame;
reduceRect.size.height = 0;
reduceRect.size.width = 0;
reduceRect.origin.x = -50;
reduceRect.origin.y = animeView.center.y;
animeView.alpha = 0;
[animeView setFrame:reduceRect];
} completion:nil];
}];
EDIT 2:
A answer to you question in the comments:
You can execute animations simultaneous by creating a CAAnimationGroup.
Also I'm using a image to create the resize of content effect.
Example:
//Create a screenshot of your UIView... Still animeView in this example
UIGraphicsBeginImageContext(animeView.bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[animeView.layer renderInContext:context];
UIImage *screenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//Add the image as subview:
UIImageView * imageView = [[UIImageView alloc] initWithImage:screenShot];
[animeView addSubview:imageView];
//A cornerRadius animation:
CABasicAnimation *radiusAni = [CABasicAnimation animationWithKeyPath:#"cornerRadius"];
radiusAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
radiusAni.fromValue = [NSNumber numberWithFloat:0.0f];
radiusAni.toValue = [NSNumber numberWithFloat:50.0f];
//A stretch animation:
CABasicAnimation *stretchAni = [CABasicAnimation animationWithKeyPath:#"transform.scale.x"];
stretchAni.fromValue = [NSNumber numberWithDouble:1];
stretchAni.toValue = [NSNumber numberWithDouble:(animeView.frame.size.width+100)/animeView.frame.size.width];
//A slide animation:
CABasicAnimation *slideAni = [CABasicAnimation animationWithKeyPath:#"transform.translation.x"];
slideAni.fromValue = [NSNumber numberWithDouble:0];
slideAni.toValue = [NSNumber numberWithDouble:-100];
//A opacity animation:
CABasicAnimation *opacityAni = [CABasicAnimation animationWithKeyPath:#"opacity"];
opacityAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
opacityAni.fromValue = [NSNumber numberWithFloat:1];
opacityAni.toValue = [NSNumber numberWithFloat:0];
//The animationgroup
CAAnimationGroup *animGroup = [CAAnimationGroup animation];
//Add them to the group:
[animGroup setAnimations:[NSArray arrayWithObjects:radiusAni, opacityAni, slideAni, stretchAni, nil]];
//Set the properties:
[animGroup setDuration:3.0];
[animGroup setRemovedOnCompletion:NO];
[animGroup setFillMode:kCAFillModeForwards];
//Execute all the animations in the group:
[animeView.layer addAnimation:animGroup forKey:nil];
Then you'll have 4 animations executing at the same time and the resize of the content when stretching, shrinking or whatever you plan to do ;-)
If you want to animate changes in shape you could use a CAShapeLayer. That takes a CGPath that describes the shape to be drawn. It can only draw 1 path, and that drawing can only use a single line color and a single fill color. You can't draw some lines in color 1 and other lines in color 2, etc.
Once you have a CAShapeLayer you can animate changes to the CGPath object associated with the shape layer. The trick to making it work is that the starting and ending CGPath need to have the same number of control points. If you use a path that has 3 linked bezier paths, the end path needs to use 3 linked bezier paths also, but you can move the points around as much as you want.
I've found through experimentation that you can't animate changes to arcs in bezier curves. The reason is that internally, the system generates a series of bezier curves to create the arc, and there are more bezier segments the larger the arc angle.

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

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.

Resources