Switching views using Core Animation not working? - iphone

Currently I am having a issue switching views using Core Animation. I want to fade through black switching to my next view.
Right now it does not do anything besides lose touch events from my original view.
What am I doing wrong in the code below?
Edit1 Code:
- (void)changeView1ToView2 {
CABasicAnimation *fadeout= [CABasicAnimation animationWithKeyPath:#"opacity"];
[fadeout setDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:)];
[fadeout setToValue:[NSNumber numberWithFloat:0]];
[fadeout setDuration:0.5];
[[self.view layer] addAnimation:fadeout forKey:#"alpha"];
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
[self.view addSubview:self.view2.view];
self.view2.view.frame = [UIScreen mainScreen].bounds;
[self.view2.view setAlpha:0];
CABasicAnimation *fadein = [CABasicAnimation animationWithKeyPath:#"opacity"];
[fadein setToValue:[NSNumber numberWithFloat:1.0]];
[fadein setDuration:0.5];
[[self.view2.view layer] addAnimation:fadein forKey:#"alpha"];
}
Ok I added self, look at my new code above. view2 is a UIViewController, thats why I am doing .view after it. The app is only going to be available on iOS 5 or up so thats not a problem. But what I am trying to achieve is switching views using Core Animation, and have each UIViewController manage their own views. I am just switching views using Core Animation instead of usual means.

If you're looking to have only one root view on screen at one time (and by the looks of that call to [UIScreen mainScreen].bounds, you are), then I'd suggest swapping the views at the UIWindow level. Without animations, this would look something like this:
// Assuming UIViewControllers called view1 and view2 as members of some
// (non-UIViewController) controller class (self, in this case)
//and that view1.view is in the application's window's subviews collection
[self.view1.view removeFromSuperview];
[[UIApplication sharedApplication].delegate.window addSubview:self.view2.view];
In terms of not seeing the views actually swap, you need to ensure that your animation preserves the changes you make during the animation. Specifically, you need to set the following:
myAnimation.fillMode = kCAFillModeForwards;
myAnimation.removedOnCompletion = NO;
Your methods can then be adjusted to take all this into account. For example, your animationDidStop:finished: method might look like this:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
[self.view1.view removeFromSuperview];
[self.view2.view setAlpha:0];
[[UIApplication sharedApplication].delegate.window addSubview:self.view2.view];
CABasicAnimation *fadein = [CABasicAnimation animationWithKeyPath:#"opacity"];
[fadein setToValue:[NSNumber numberWithFloat:1.0]];
[fadein setDuration:0.5];
fadein.fillMode = kCAFillModeForwards;
fadein.removedOnCompletion = NO;
[[self.view2.view layer] addAnimation:fadein forKey:#"alpha"];
}
You may need to muck around with it a bit to ensure that everything is firing correctly.

Related

iOS view transitions using blocks

I need to switch from 3 views of same viewcontroller. I am reaching it properly but I always get a fade transition. I do not understand how exactly works. Which parameter defines type of transition? setType or layer forKey:? I tried both but I always get same effect! Thank you
CATransition *trans =[CATransition animation];
trans.delegate = self;
[trans setDuration:2];
[trans setType:kCATransitionFromTop];
[trans setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
CALayer *layer = self.view.layer;
[layer addAnimation:trans forKey:kCATransitionMoveIn];
[self.view addSubview:vistaSocial];
To transition between multiple views you can simply use the +transitionFromView:toView:duration:options:completion: method of UIView. The options allow you to specify which type of transition you would like.
For example:
[UIView transitionFromView:view1 toView:view2 duration:0.35 options:UIViewAnimationOptionTransitionFlipFromRight completion:nil];
http://developer.apple.com/library/ios/#documentation/uikit/reference/uiview_class/uiview/uiview.html

Is there an alternative way to perform this animation using animation blocks?

I'm currently performing a curl up animation by doing the following:
CATransition *animation = [CATransition animation];
animation.type = #"pageCurl";
animation.subtype = kCATransitionFromTop;
animation.fillMode = kCAFillModeForwards;
animation.duration = 1;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[[self.view.window layer] addAnimation:animation forKey:nil];
This animation will simply perform a page curl animation but in the end you are left looking at the same view that you started out with. No REAL transition ever occurred.
Now using animation blocks I know you can do something to the effect of:
[UIView transitionFromView:self.view
toView:aNewView // a view to transition to
duration:1
options:UIViewAnimationTransitionCurlUp|UIViewAnimationOptionCurveEaseIn
completion:NULL];
However, using animation blocks you are transitioning to a new view, aNewView, which is different from the CATransition animation above which reuses the same view (no real transition ever occurs). The problem with the animation block is that you have to actually create the new view to transition to which is cumbersome in my case because the view is rather complicated and I'd rather not create a UIView subclass.
Is there a way to perform the above CATransition animation using animation blocks while getting around the difficulties of having to rebuild a view or create a custom subclass?
Ok - so I figured it out for anyone who is interested. It's actually super simple. You can simply use the method: transitionWithView:duration:options:animations:completion:
For example:
[UIView transitionWithView:self.view
duration:1
options:UIViewAnimationOptionTransitionCurlUp|UIViewAnimationCurveEaseIn
animations:^{ // do anything you want here }
completion:NULL];
That's it. This will show a transition animation back to the same view. You can make any changes you want to the new view (maybe display some new text, whatever...) in the animation block.
I hope this helps someone out down the line...

Custom UITableViewCell and animation on setSelected:animated:

I have a UITableViewCell subclass that does its drawing in a drawRect: method. The whole rectangle is custom drawn, including the background.
I was able to get very complex cells while keeping the scrolling very smooth.
My problem: I call [table deselectRowAtIndexPath:path animated:YES]; whenever the view appears, in order to comply with Apple's HIG. However, no animation occurs. It worked when I had a custom view (created with subviews) that was transparent (so Apple's background would appear below), of course. Now it doesn't.
My drawRect: is called once during the "animation time", about halfway through. I think this happens because it's animating the highlighted property of the cell from 1 to 0 and it snaps to 0 when it drops below 0.5.
How can I animate this transition? My guess would be to use the usual beginAnimations: etc. and animate a custom floating point field in my cell object from 1 to 0. Will this call drawRect: repeatedly to animate?
Update
I managed to get this almost working. I've overridden setSelected:animated: like so:
- (void) setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:NO];
if (animated) {
[CATransaction begin];
CATransition* animation = [CATransition animation];
animation.type = kCATransitionFade;
animation.duration = 0.6;
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[view.layer addAnimation:animation forKey:#"deselectRow"];
[CATransaction commit];
}
}
This works perfectly if the table view is on-screen. But if I'm returning to the table view from navigation (back), instead of fading from selected to not selected, it fades from invisible to not selected. What can cause this?
A little late answer, but might still be useful to you and others. What you need to do, is to assign your custom selected view before messaging the super, like so:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
UIView *view = [[UIView alloc] initWithFrame:self.frame];
view.backgroundColor = [UIColor colorWithRed:.9 green:.0 blue:.125 alpha:1.0];
self.selectedBackgroundView = view;
[super setSelected:selected animated:animated];
}

iPhone SDK: Optimize UIModalTransitionStyleFlipHorizontal

I want to flip my new ModalView with very high performance, but the new View has a lot of subviews so the performance of the Flip-Effect is very bad. Actually i do it with:
[controller setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:backSideController animated:YES];
I also tried it with
CATransition *transition = [CATransition animation];
transition.duration = 0.75;
[transition setType: #"flip"];
[transition setSubtype:#"fromRight"];
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[transition setFillMode:#"extended"];
[[self.view layer] addAnimation:transition forKey:nil];
[self.view addSubview: backSideController.view];
[CATransaction commit];
With Core-Animation it works a little bit faster ... ware there further ways to opimize this task? e.g. Adding view when animation stops and just flipping a screenshot until animation stops?
Try accessing backsideController.view before you begin the animations. This will cause backsideController's loadView and viewDidLoad to be called. I'm guessing that this is your performance hit -- that all that loading & allocating is causing the animation to stutter.
You don't need anything fancy, you can do something like:
if (backsideController.view == nil)
NSLog(#"Where's my view?!");
before your other code, above.
I don't believe that having many-many subviews causes performance problems on the flip; I'm pretty sure (without looking at your code or checking in instruments, which you should do!) that the problem is the time it takes to load and allocate the view components.
Also, I'd stick with presentModalViewController, if it does what you want. Having all that extra code in your 2nd example -- unless it's needed for functionality -- is just maintenance headache.

After Animation, View position resets

I am trying to make a view slide from top to bottom. This is not a big deal, I used CABasicAnimation for this. The problem is when I want to remove the view. I use this animation.
CABasicAnimation *animation;
animation = [CABasicAnimation animationWithKeyPath:#"position"];
[animation setDelegate:self];
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(self.view.layer.position.x, 0 - self.view.bounds.size.height / 2)];
animation.fromValue = [NSValue valueWithCGPoint:self.view.layer.position];
animation.autoreverses = NO;
animation.repeatCount = 0;
animation.duration = 0.25;
animation.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut];
[self.view.layer addAnimation:animation forKey:#"moveX"];
Which animates the view perfectly. But, after the animation finishes, my view appears again. So I added this line :
[self.view removeFromSuperview];
Which removes the view, but with no animation. So I decided to add the remove code to this delegate:
-(void) animationDidStop:(CAAnimation *) animation finished:(bool) flag
So now, the animation works, the view disappears, but sometimes, I can see the view appear and disappear faster, is like after the animation, the view appears, then the animationDidStop delegate is called, and the view disappears, obviously this is awful. What am I doing wrong?
Might want to set these properties. They cause the presentation to be preserved at the end of the animation.
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
Then the "animationDidStop:" method can be used to remove the view at the end of the animation:
-(void) animationDidStop:(CAAnimation *) animation finished:(bool) flag {
if (animation == [containerView.layer animationForKey:#"moveX"]) {
// remove view here, add another view and/or start another transition
}
}
Well, according to the Apple sample "MoveMe", this (removedOnCompletion) should work, however, it doesn't seem to.
So, add these lines after your code:
[self.view.layer addAnimation:animation forKey:#"moveX"];
self.view.layer.position = [animation.toValue CGPointValue];
This ensures that after the animation runs, the layer is properly positioned.
I had this issue when performing several animations in an animation group. I had to set a couple properties on the animation group itself, not the individual animations.
CAAnimationGroup *animGroup = [CAAnimationGroup animation];
// MAKE SURE YOU HAVE THESE TWO LINES.
animGroup.removedOnCompletion = NO;
animGroup.fillMode = kCAFillModeForwards;
animGroup.animations = [NSArray arrayWithObjects:moveAnim, scaleAnim, nil];
animGroup.duration = tAnimationDuration;
[tImageView.layer addAnimation:animGroup forKey:nil];
This one bit me too. You want to set the animation's removedOnCompletion flag to NO. It defaults to YES, which means after the animation is complete, it's removed, and the view reverts to its initial state.
Setting the view to hidden as Rob suggests should do it.
For properties of properties I would stick with the ObjC 2.0 style like you already have in your code.
set.view.hidden = YES;
Can you set the view's hidden property to YES?
I think it would be:
self.view.hidden = YES;
But it might be:
[self.view setHidden:YES];
I turns out I am pretty lame at figuring out the proper way to access properties of properties.