iphone - undo or reverse kCATransitionPush to send image off screen - ios

I am currently sliding in an animated image from the right of the screen using CATransition:
CATransition *transition = [CATransition animation];
transition.duration = TRANSITION_DURATION;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[self.layer addAnimation:transition forKey:nil];
self.image = [UIImage animatedImageNamed:prefix duration:ANIMATION_DURATION];
My question is, how do I slide the image out? Once the image animation cycles through, I want to send it off the screen in the direction from whence it came, i.e. TransitionToRight, but there doesn't seem to be such a transition type. Please suggest how I might accomplish this reverse transition.
Here is how I might write it, if such a reverse transition existed:
[self performSelector:#selector(removeAnimatedImage) withObject:nil afterDelay:ANIMATION_DURATION];
and inside removeAnimatedImage, I would create another CATransition animation with this reverse direction to send it off the screen.

Did you try the kCATransitionFromLeft version of the push transition? It should be the inverse of FromRight.

Not the ideal solution, but one hack is to either animate a change in frame bounds, or applying a translation transform animation:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:TRANSITION_DURATION];
if (enteredFromRight) {
self.transform = CGAffineTransformMakeTranslation(SCREEN_SPACE_WIDTH, 0);
} else {
self.transform = CGAffineTransformMakeTranslation(-SCREEN_SPACE_WIDTH, 0);
}
[UIView commitAnimations];

Related

iOS: Core Animation UIView flip. How to make two turnover?

I made CATransition animation, I have 2 UIView that flips. Code below makes one turnover, how can I make 2 turnovers? Show me example please. Here is my flip code:
CATransition* transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type =#"flip";// kCATransitionPush;
transition.subtype = #"fromRight"; //kCATransitionFromRight;
transition.duration = 0.3;
// Add the transition animation to both layers
[self.fitstUIView.layer addAnimation:transition forKey:#"transition"];
[self.secondUIView.layer addAnimation:transition forKey:#"transition"];
Think of it like this is a coin that flips in the air.
EDIT
I also want that first flip was much faster than the second flip. Some kind of slow effect.
My code doing things fine for one spin, but trouble is that if I just add this transition to layer more than once, spin will be only once. So, I need to nest CATransitions to one (CAAnimation group? can't make this thing to work for me) and add with add animation method.
Have you tried setting:
transition.repeatCount = 2;
Let me know if it helps.
How about using nested animation blocks to acheive this. Something like this:
[UIView transitionWithView:VIEW_THAT_YOU_WANT_TO_ANIMATE duration:0.5 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
} completion:^(BOOL finished)
{
[UIView transitionWithView:VIEW_THAT_YOU_WANT_TO_ANIMATE duration:0.2 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
} completion:^(BOOL finished)
{
}];
}];

Implicit animation on CALayer "contents" property

According to the core animation documentation, setting the layer contents should trigger an implicit 0.25 animation that will transition between the new and old images.
I also see many places where people are asking how to remove this implicit animation but for some reason when I try this on my project, I get an instant swap of images.
Reading some more into the documention I saw this code snipped:
- (id<CAAction>)actionForLayer:(CALayer *)theLayer
forKey:(NSString *)theKey {
CATransition *theAnimation=nil;
if ([theKey isEqualToString:#"contents"]) {
theAnimation = [[CATransition alloc] init];
theAnimation.duration = 1.0;
theAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
theAnimation.type = kCATransitionPush;
theAnimation.subtype = kCATransitionFromRight;
}
return theAnimation;
}
Which implies that "contents" is not implicitly animated.
I would be very interested to understand this better.
OK, I'm copying some code from an app of mine. First I usually get CATransition not with alloc..init.. but using +animation. Second I'm not seeing that you are adding the transition to a layer. Third I'm not sure that CATransition are implicitly animated, CALayer properties yes.
CATransition *transition = [CATransition animation];
transition.duration = 1;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = slideCATransitionCompareTable[ arc4random() % 4]; //to get a random subtype
[self.slideShowReceiptImageView.layer addAnimation:transition forKey:nil];

fade View IN and OUT

Good Morning everyone,
I'm totally confused with this problem.
I have 3 UIWebViews and what should hapen is webView1 fades in (that works) fades out und WebView2 fades in......
I made it so far with:
CATransition *Animation = [CATransition animation];
[Animation setDuration:4.0];
[Animation setType:kCATransitionFade];
[Animation setSubtype:kCATransitionFade];
[Animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
transitioning = YES;
if (transitioning) {
[self.webView1.layer addAnimation:Animation forKey:nil];
self.webView1.hidden = YES;
self.webView2.hidden = NO;
can anyone help me with that?
And when it fades in the webView fades from white even the background color is set to an other color!
can't I effect the color?
You should use UIView implicit animations. For instance, a cross fade from webView1 to webView2:
[UIView beginAnimations:#"fade" context:nil];
self.webView1.alpha = 0.0;
self.webView2.alpha = 1.0;
[UIView commitAnimations];
If you wanna execute some code after the animation finished, insert this between begin and commit:
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeAnimationDidStop:finished:context:)];
and create the didStop method with the signature
- (void)fadeAnimationDidStop:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context`
transition.type =kCATransitionMoveIn;
transition.subtype =kCATransitionFade;

Glitch when sliding in UIView with kCATransitionMoveIn

I have a UINavigationController whose UIView slides in from the bottom of the screen when the user presses a button.
Immediately after I set the view's "hidden" property to NO, though, the UINavigationController's view sometimes appears fully in place for one frame, as if the animation was finished already.
This is the code that shows/hides the view:
- (void)showGUI: (bool)show
{
CATransition *transition = [CATransition animation];
transition.duration = 0.5;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
if (!show)
{
transition.type = kCATransitionReveal;
transition.subtype = kCATransitionFromBottom;
}
else
{
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromTop;
}
[navController.view.superview.layer addAnimation:transition forKey:nil];
navController.view.hidden = !show;
}
CATransition animations are applied when layers are added/removed from the layer you add the animation to. If toggling the hidden property doesn't work, then try removing the view instead.

Animate between two states of a view, using custom animation

I would like to animate between two states of a view. Say, for example, I have a view with a label and when I change the text of the label an animation renders that change as a page flipping.
Now you can of course do this with a [UIView setAnimationTransition:forView:cache:]:
- (IBAction)nextPage {
[UIView beginAnimation:nil context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:pageView cache:NO];
label.text = #"page 2";
[UIView commitAnimations];
}
- (IBAction)previousPage {
[UIView beginAnimation:nil context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:pageView cache:NO];
label.text = #"page 1";
[UIView commitAnimations];
}
...but then you cannot use your own custom animation, you are stuck to the built-in animations (they're nice but they're not tailored to my needs).
So the other option is to add a CAAnimation to the view's layer:
- (IBAction)nextPage {
CAAnimation *animation = [self animationWithDuration:1 forward:NO];
[pageView.layer addAnimation:animation forKey:#"pageTransition"];
label.text = #"page 2";
}
- (IBAction)previousPage {
CAAnimation *animation = [self animationWithDuration:1 forward:YES];
[pageView.layer addAnimation:animation forKey:#"pageTransition"];
label.text = #"page 1";
}
Then you are free to set whatever animation Core Animation enables you to do. This works well if I define a CATransition animation, for example a kCATransitionReveal: a view in the "page 2" state appears below the view in the "page 1" state as it slips out.
- (CAAnimation *)animationWithDuration:(float)duration forward:(BOOL)forward {
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionReveal];
[animation setSubtype:forward?kCATransitionFromLeft:kCATransitionFromRight];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
animation.duration = duration;
return animation;
}
But when I define the animation to be for example a CABasicAnimation, only one state of the view is visible.
- (CAAnimation *)animationWithDuration:(float)duration forward:(BOOL)forward {
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / -1000;
transform = CATransform3DRotate(transform, M_PI, 0.0f, 1.0f, 0.0f);
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform"];
if(forward) {
animation.fromValue = [NSValue valueWithCATransform3D:transform];
} else {
animation.toValue = [NSValue valueWithCATransform3D:transform];
}
animation.duration = duration;
return animation;
}
Instead, I would like the view in the "page 1" state to remain visible until the end of the animation while the view in the "page 2" state comes into frame, exactly as it behaves with a transition animation.
Of course, I could always mess with duplicating the view and having one appear as a sibling view while I animate the frontmost one and remove it from superview on completion... but there must be a much more straight way to achieve this rather simple animation effect without messing with the views.
Probably something to tell the layer, but then I don't know what, and that's where I need your help, guys :)
Thanks!
I recently did a custom slide transition between subviews in a controller. My approach was to grab a bitmap of the view-out and the view-in, add them to a view and animate that view. At the end you can just remove the transition view and show the view-in. Here's a snippet the transition method:
-(void) transitionToView:(UIView *)viewIn lastView:(UIView *)viewOut slideRight:(BOOL)isRight {
UIGraphicsBeginImageContext(viewOut.frame.size);
UIImageView *bitmapOut = [[UIImageView alloc] initWithFrame: viewOut.frame];
[viewOut.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewOutImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
bitmapOut.image = viewOutImage;
UIImageView *bitmapIn = [[UIImageView alloc] initWithFrame: viewIn.frame ];
bitmapIn.frame = CGRectMake(isRight ? 320 : -320, bitmapIn.frame.origin.y, bitmapIn.frame.size.width, bitmapIn.frame.size.height);
UIGraphicsBeginImageContext(viewIn.frame.size);
[viewIn.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewInImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
bitmapIn.image = viewInImage;
[self.view addSubview:transitionContainer];
[transitionContainer addSubview:bitmapIn];
[transitionContainer addSubview:bitmapOut];
[self removeAllViews];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(swapViewsAtEndOfTransition:)];
transitionContainer.frame = CGRectMake(isRight ? -320 : 320, 0, 640, 411);
[UIView commitAnimations];
[bitmapOut release]; bitmapOut = nil;
[bitmapIn release]; bitmapIn = nil;}
Then, in the swapViewsAtEndOfTransition selector you can update the views accordingly.
Well, you can create a layer, set it content to an image representing your view final state, than apply the animation to this layer. When the animation is done you can remove the layer and switch view state.
I think this will work better than instancing whole view.
Years have passed but I guess I found a solution for you. Just use kCATransitionPush instead of kCATransitionReveal. Like this:
- (CAAnimation *)animationWithDuration:(float)duration forward:(BOOL)forward {
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionPush];
[animation setSubtype:forward?kCATransitionFromLeft:kCATransitionFromRight];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
animation.duration = duration;
return animation;
}

Resources