Summary
I have a content UIViewController that presents a settings UIViewController using a custom transition. The presentation is with presentViewController:animated:completion:.
When I later dismiss the settings with dismissViewControllerAnimated:completion:, the presenting controller is suddenly jumped back to it's initial position prior to the settings controller presentation.
I have a work around for this on the device but not the simulator. However, I'd like to know what I'm doing wrong rather than hack in a bodge that makes it go away. I also plan to make this animation interactive, and I suspect this issues will amplify when I do this.
Custom Transition – Opening the hood
The desired effect is that the presenting controller slides down the screen, and the presented controller is seen to be lying behind it from where it lifts up to fill the screen. The top of the presenting controller remains on-screen during the lifetime of use of the presented controller. It stays at the bottom of the screen, but above the presented controller.
You could imagine lifting the bonnet on a car (the front presenting controller) to see the engine behind (the presented settings), but the bonnet stays visible at the bottom for a bit of context.
I plan to refine this so that the presenting controller really appears to lift up with perspective in a 3d way, but I've not got that far, yet.
When the settings are dismissed, the original presenting controller (bonnet) should slide back up the screen and the presented controller (settings) sink back slightly (closing the bonnet).
Code
Here's the method that toggles the settings on and off the screen (it's just called by a UIButton). You'll notice that the presenting view controller sets itself up as the <UIViewControllerTransitioningDelegate>.
-(void) toggleSettingsViewController
{
const BOOL settingsAreShowing = [self presentedViewController] != nil;
if(!settingsAreShowing)
{
UIViewController *const settingsController = [[self storyboard] instantiateViewControllerWithIdentifier: #"STSettingsViewController"];
[settingsController setTransitioningDelegate: self];
[settingsController setModalPresentationStyle: UIModalPresentationCustom];
[self presentViewController: settingsController animated: YES completion: nil];
}
else
{
[self dismissViewControllerAnimated: YES completion: nil];
}
}
To implement <UIViewControllerAnimatedTransitioning> the presenting view controller also just returns itself as the <UIViewControllerAnimatedTransitioning>
-(id<UIViewControllerAnimatedTransitioning>) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
return self;
}
-(id<UIViewControllerAnimatedTransitioning>) animationControllerForDismissedController:(UIViewController *)dismissed
{
// Test Point 1.
return self;
}
So finally, the presenting view controller will receive animateTransition::
-(void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *const fromController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *const toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
const BOOL isUnwinding = [toController presentedViewController] == fromController;
const BOOL isPresenting = !isUnwinding;
UIViewController * presentingController = isPresenting ? fromController : toController;
UIViewController * presentedController = isPresenting ? toController : fromController;
if(isPresenting)
{
// Add the presented controller (settings) to the view hierarchy _behind_ the presenting controller.
[[transitionContext containerView] insertSubview: [presentedController view] belowSubview: [presentingController view]];
// Set up the initial position of the presented settings controller. Scale it down so it seems in the distance. Alpha it down so it is dark and shadowed.
presentedController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
presentedController.view.alpha = 0.7;
[UIView animateWithDuration: [self transitionDuration: transitionContext] animations:^{
// Lift up the presented controller.
presentedController.view.transform = CGAffineTransformMakeScale(1.0, 1.0);
// Brighten the presented controller (out of shadow).
presentedController.view.alpha = 1;
// Push the presenting controller down the screen – 3d effect to be added later.
presentingController.view.layer.transform = CATransform3DMakeTranslation(0,400,0);
} completion: ^(BOOL finished){
[transitionContext completeTransition: ![transitionContext transitionWasCancelled]];
}];
}
else
{
// Test Point 2.
// !!!This line should not be needed!!!
// It resets the presenting controller to where it ought to be anyway.
presentingController.view.layer.transform = CATransform3DMakeTranslation(0,400,0);
[UIView animateWithDuration: [self transitionDuration: transitionContext] animations:^{
// Bring the presenting controller back to its original position.
presentingController.view.layer.transform = CATransform3DIdentity;
// Lower the presented controller again and put it back in to shade.
presentedController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
presentedController.view.alpha = 0.4;
} completion:^(BOOL finished) {
[transitionContext completeTransition: ![transitionContext transitionWasCancelled]];
}];
}
}
-(NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 0.5;
}
Problem
In the code above, I've indicated !!!This line should not be needed!!!.
What's happening is that between Test Point 1 and Test Point 2 the screen position of the presenting view controller is reset to be the default full screen bounds. So, instead of being at the bottom of the screen ready to animate back up again smoothly, it suddenly jumps up the screen to position that it is meant to smoothly animate too!
I've tried various approaches to animating the presenting view controller down the screen:
I've changed its view's frame.
I've changed its view's transform.
I've changed its view's layer's 3d transform.
In all cases, at Test Point 1, when the transition delegate is asked for, the presenting controller is set up as I would expect. However, in all cases, at Test Point 2, the presenting view controller has lost the correct position and has been "cleared" to have the normal full screen position that I want to animate it to.
In the work around above I explicitly relocate the presenting view controller back to where it should be at the start of the animation with !!!This line should not be needed!!!. This seems to work on the device with the current version of iOS 7. However, on the simulator, the controller is visible at the cleared position for at least one frame.
I am suspicious that I am doing something else wrong, and that I'm going to get in to trouble with my workaround just masking another problem.
Any ideas what's going on? Thanks!
A few potential gotchas with dismissal of modally presented view controllers using custom transition animations:
Add the presented ("to") view to the container, then bring the presented view front. Don't add the presenting view as you might remove it from its current superview.
On dismiss, UIKit sets the alpha of the presented view to 0 before animateTransition is called. So you'll want to set it to 1.0 or whatever it was at the completion of the present before firing off your dismiss animation(s).
Likewise for the presented view's transform. On dismiss it gets reset to identity before your animateTransition is called.
Given all that, I think this should work:
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containerView = transitionContext.containerView;
const BOOL isUnwinding = [toController presentedViewController] == fromController;
const BOOL isPresenting = !isUnwinding;
UIViewController *presentingController = isPresenting ? fromController : toController;
UIViewController *presentedController = isPresenting ? toController : fromController;
[containerView addSubview:presentingController.view];
[containerView bringSubviewToFront:presentingController.view];
if(isPresenting)
{
// Set up the initial position of the presented settings controller. Scale it down so it seems in the distance. Alpha it down so it is dark and shadowed.
presentedController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
presentedController.view.alpha = 0.7;
[UIView animateWithDuration: [self transitionDuration: transitionContext] animations:^{
// Lift up the presented controller.
presentedController.view.transform = CGAffineTransformMakeScale(1.0, 1.0);
// Brighten the presented controller (out of shadow).
presentedController.view.alpha = 1;
// Push the presenting controller down the screen – 3d effect to be added later.
presentingController.view.layer.transform = CATransform3DMakeTranslation(0,400,0);
} completion: ^(BOOL finished){
[transitionContext completeTransition: ![transitionContext transitionWasCancelled]];
}];
}
else
{
presentedController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
presentedController.view.alpha = 0.7;
[UIView animateWithDuration: [self transitionDuration: transitionContext] animations:^{
// Bring the presenting controller back to its original position.
presentingController.view.layer.transform = CATransform3DIdentity;
// Lower the presented controller again and put it back in to shade.
presentedController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
presentedController.view.alpha = 0.4;
} completion:^(BOOL finished) {
[transitionContext completeTransition: ![transitionContext transitionWasCancelled]];
}];
}
}
Initially, I thought about using CATransition to have custom transition effect when presentViewController:animated:completion: and dismissViewControllerAnimated:completion: a View Controller. But you want to show a portion of View Controller when the setting View Controller is presented, then I think CATransition would not help because you don't have full control of how far you want to move the View Controller.
I think the easiest way is to have one single View Controller with two full screen UIView. For the first UIView (View Controller's view, that is, self.view), you layout the setting, and on the second UIView, it's the regular View. In the ViewDidLoad, you add the 2nd view by using [self.view addSubview:2ndView];. Later when you want to present the setting view, you can do
CGRect frame = secondView.frame;
frame.origin.y = the_y_coordinate_you_like;
UIView animateWithDuration:0.2 animations:^{
secondView.frame = frame;
}];
then do the other way to bring the 2ndView back.
Related
I'm building an iOS 8 app and using UIPresentationController to present a view controller in a custom way. (see my previous question about this here: Replicating the style of the iOS Mail App's Compose Function).
The issue I'm having is that when I present the controller, the navigation bar starts off as 64 points tall and then jumps/shrinks back to 44 once its presentation is finished. My guess is that the view controller realizes it is not covering the status bar and so it shrinks itself down once it comes to its final resting position. I'd like for the navigation bar to be 44 points tall the entire time and not jump/shrink.
The image below is what the view controller looks like at the end of the presentation. It is also what I want it to look like the entire time. Any thoughts on how to keep the navigation bar at 44 points the entire time?
UPDATE (3/24/2015):
I referenced a blog post from a while back to find some more information on this issue. Basically, UINavigationController draws its navigation bar either 64 or 44 points tall depending on if its view's frame is matched up with the app's window or not. So I need some way of telling the navigation controller that its final resting position will not be lined up with the window, and that the nav bar should be drawn 44 points tall.
http://blog.jaredsinclair.com/post/61507315630/wrestling-with-status-bars-and-navigation-bars-on
Finally found an answer to this question. It's explained in this previous stack overflow post:
Navigation bar gets adjusted after calling completeTransition: in custom transition
Thank you for not making me use my hard earned rep to start a bounty!
I had an issue a bit like yours, where the navigation bar would resize after [transitionContext completeTransition:YES] was called, based on visual contiguity of the navigationBar's frame sharing a border with the UIWindow's top. My navigation bar was nowhere near the top, so it resized itself to 44px instead of the normal "extend-under-the-status-bar" 64px. To get around this, I simply completed the transition before I animated my toViewController's alpha and position. That is, once everything was positioned properly to be animated in, I called completeTransition: to let the navigationController adjust itself while invisible. So far, this hasn't had any unintended side-effects, and the additional alpha in, move frame animations still continue after you completeTransition.
Here is my animateTransition: method in my presentation animator class that conforms to <UIViewControllerAnimatedTransitioning>
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *presentedViewController = self.presenting ? toViewController : fromViewController;
UIView *containerView = [transitionContext containerView];
NSTimeInterval animationDuration = [self transitionDuration:transitionContext];
if (self.presenting) {
containerView.alpha = 0.0;
presentedViewController.view.alpha = 0.0;
[containerView addSubview:presentedViewController.view];
[UIView animateWithDuration:animationDuration delay:0 options:kNilOptions animations:^{
containerView.alpha = 1.0;
} completion:^(BOOL finished) {
presentedViewController.view.frameTop += 20;
//I complete the transition here, while my controller's view is still invisible,
// but everything is in its proper place. This effectively positions everything
// for animation, while also letting the navigation bar resize itself without jarring visuals.
[transitionContext completeTransition:YES];
//But we're not done quite yet...
[UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
presentedViewController.view.frameTop -= 20;
presentedViewController.view.alpha = 1.0;
} completion:nil];
}];
}
if (!self.presenting) {
[UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
presentedViewController.view.alpha = 0.0;
presentedViewController.view.frameTop += 20;
} completion:^(BOOL finished) {
[UIView animateWithDuration:animationDuration delay:0 options:kNilOptions animations:^{
containerView.alpha = 0.0;
} completion:^(BOOL done) {
[transitionContext completeTransition:YES];
}];
}];
}
Hope this helps anyone that finds themselves in my position!
I am trying to make a custom expand viewcontroller animation in iOS.
It's a iPad application and has a big square button of size 160*160 in the home screen. I have connected a modal segue to the next viewcontroller scene. What I am trying to achieve is when I tap on the UIButton the destination viewcontroller should expand from the button and shall be animated to full screen with animation completion.
I have subclassed NSObject and created ExpandAnimationController, implemented transitionDuration and animateTransition methods. But the I am stuck at a point to determine the initial frame for the destination viewcontroller's view.
I know for one button I can set frame statically but where in a scenario appears that there are multiple buttons and each button has to a modal segue to a different view controller than how can I pass the buttons frame to the animation controller to set the initial view frame.
I am doing this only for learning purpose after trying raywanderlich's custom view controller transition tutorial. So the problem now is passing a frame object from "Source controller to Animation controller". I've already searched, internet is not much populated with custom transition issues. Any help will be appreciated.
Here is the code I've tried, in ExpandAnimationController,
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
// 1. Fetch all the required objects.
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIView *containerView = [transitionContext containerView];
CGRect finalFrame = toVC.view.frame;
// 2. Set initial frames.
// This is where I am stuck.
CGRect initialFrame = CGRectZero;
toVC.view.frame = initialFrame;
[containerView addSubview:toVC.view];
// 3. Do the animation.
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration animations:^{
fromVC.view.alpha = 0.5;
toVC.view.alpha = 0.5;
toVC.view.frame = finalFrame;
} completion:^(BOOL finished) {
fromVC.view.alpha = 1.0;
toVC.view.alpha = 1.0;
toVC.view.frame = finalFrame;
[transitionContext completeTransition:YES];
}];
}
In the source controller I've adopted UIViewControllerTransitioningDelegate, created a ExpandAnimationController instance and used like below,
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
return _expandAnimationController;
}
But after - prepareForSegue is called I want to pass the sender button frame to the transition animation controller.
Thanks in advance, Happy coding !!
There are many approaches on how you could do this, like an iVar to your transition or transitioning delegate that you could pass in the button rect, but I'm going to suggest a simpler approach (although with a caveat):
First assign a unique Tag to your UIButton either by code, or in Interface Builder.
In this example I'm using the 111 tag:
In your - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext you can get a reference to that button from your ViewController:
CGRect myButtonRect = CGRectZero;
UIButton *myButton = (UIButton*)[fromVC.view viewWithTag:111];
if (myButton) {
myButtonRect = myButton.frame;
NSLog(#"button Frame:%#",NSStringFromCGRect(myButtonRect));
}
What's the caveat?
If you are using the same animation to transition back, the From and To View controllers are going to be reversed.
Also if you use the same Transition on another View Controller and that View Controller has the same tag number for another object, you will get that object and not your Button.
So if you use this approach make sure to use a globally Unique Tag for your entire App, like 32565 (random number here that is big enough so you won't re-use it again)
Now if you have multiple buttons, you cannot use the above approach, so use an iVar to your custom transition:
#interface MyCustomTransition : NSObject <UIViewControllerAnimatedTransitioning>
#property (nonatomic, assign) CGRect initialFrame;
#end
Then in the view controller you are using your custom transition, just pass in the frame:
MyCustomTransition *myTransition = [MyCustomTransition new];
myTransition.initialFrame = myButton.frame;
And finally in your - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext get the iVar value from self.initialFrame
You can convert CGRect to NSValue and put it into sender.
// Send it like this
[self performSegueWithIdentifier:#"someIdentifier" sender:[NSValue valueWithCGRect:yourFrame]];
Also you can retrieve it like this
// Retrieve it
CGRect frame = [sender CGRectValue];
I'm trying to do a very simple transition: one view moves half the screen to the left while the second ("to") view moves in half a screen.
I have the animation working, but when I reverse the animation, I see a flickering. The "to" view (i.e. the original view) is visible at the origin of 0,0 although I set a different frame.
I dumped the view hierarchy. The frames are set correctly (-100 0; 320 480 for the to view), but nonetheless it shows up at 0,0. Is a screenshot of the view cached somewhere for the animation?
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *container = [transitionContext containerView];
CGRect offsetCoverRect = CGRectMake(-100.0, 0.0, 320, 480);
CGRect detailsRect = CGRectMake(-100.0 + 320.0, 0.0, 320, 480);
CGRect detailsOutsideRect = CGRectMake(320.0, 0.0, 320, 480);
CGRect normalRect = CGRectMake(0.0, 0.0, 320, 480);
if (self.revealDetails)
{
toViewController.view.frame = detailsOutsideRect;
[container addSubview:toViewController.view];
}
else
{
[container insertSubview:toViewController.view belowSubview:fromViewController.view];
// reversing… set the frame to the original offset (shows at 0,0 for a moment)
toViewController.view.frame = offsetCoverRect;
}
[UIView animateKeyframesWithDuration:2 delay:0 options:0 animations:^{
if (self.revealDetails)
{
fromViewController.view.frame = offsetCoverRect;
toViewController.view.frame = detailsRect;
}
else
{
fromViewController.view.frame = detailsOutsideRect;
toViewController.view.frame = normalRect;
}
} completion:^(BOOL finished) { [transitionContext completeTransition:finished]; }];
}
Update:
It seems to be related to UIModalPresentationCustom. I need to use this so that the from view is not removed when the transition completes. However, it seems to assume that the from view controller for the reverse transition starts at 0,0.
Update 2:
Very easy to reproduce with the following code:
UIView *snapshot = [containerView snapshotViewAfterScreenUpdates:NO];
[containerView addSubview:snapshot];
The above will show the to view centered on screen, no matter what actual frame or center I set before the animation.
I know this is an old question, but I ran into the same problem and after hours of struggling, finally came up with a solution:
In the completion block of the present animation,
Create a snapshot of the fromViewController view
Perform frame changes/transforms on the snapshot
Add snapshot to the containerView
Remove the fromViewController view from the container view
In the completion block of the dismiss animation (or anywhere if its a dismiss?), remove the snapshot from the container
By removing the fromViewController's view from the container view, it does not get reset to it's initial position because it is no longer inside of the container view.
This is because your animateTransition method is being called from background.
Call your method in this way
dispatch_async(dispatch_get_main_queue(), ^
{
[self animateTransition]; // your method goes here
});
You should never call any animation or any UI related methods on background thread
I am using the following code in my presenting VC to fade in the child modal VC, and this works fine:
self.infoViewController.view.alpha = 0.0;
[self.navigationController presentModalViewController:self.infoViewController animated:NO];
[UIView animateWithDuration:0.5
animations:^{self.infoViewController.view.alpha = 1.0;}];
However I can't get it to fade out, I have tried a few things, this is the latest I tried that doesn't work:
- (IBAction)dismissAction:(id)sender
{
if ([[self parentViewController] respondsToSelector:#selector(dismissModalViewControllerAnimated:)])
{
[[self parentViewController] dismissModalViewControllerAnimated:YES];
self.parentViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
self.parentViewController.view.alpha = 0.0;
[UIView animateWithDuration:0.5
animations:^{self.parentViewController.view.alpha = 1.0;}];
} else
{
[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
self.presentedViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
self.presentedViewController.view.alpha = 0.0;
[UIView animateWithDuration:0.5
animations:^{
self.presentedViewController.view.alpha = 1.0;}];
}
}
The modal view controller is faded out but immediately, not over a time period like it is when its displayed.
This (original part) is not to take away from H2CO3's correct answer. UIModalTransitionStyleCrossDissolve does pretty-much exactly the effect you're looking for. You are just not setting the modalTransitionStyle until it's to late. Replace all of your code with these functions in there respective positions:
-(void)show{
self.infoViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:self.infoViewController animated:YES];
}
- (IBAction)dismissAction:(id)sender{
[self dismissModalViewControllerAnimated:YES];
}
Edit in response to timing being an issue: Let's talk about the offending code. We'll concentrate on just the if true part, since it's essentially identical to the else.
[[self parentViewController] dismissModalViewControllerAnimated:YES];
self.parentViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
self.parentViewController.view.alpha = 0.0;
[UIView animateWithDuration:0.5
animations:^{self.parentViewController.view.alpha = 1.0;}];
If you're looking for a reciprocal animation this isn't it. In your original animation you set the next view's alpha to 0, then presented the next view controller, then set it's view's alpha to 1. So logically you need to dismiss the view controller after the animation; This is really easy using blocks. The code would look something like this:
[UIView animateWithDuration:0.5 animations:^{
self.view.alpha = 0;
} completion:^(BOOL b){
[self.presentingViewController dismissModalViewControllerAnimated:NO];
self.view.alpha = 1;
}];
This line of code animates the view's alpha to 0, then (upon completion) dismisses the presented view controller, and sets the view's alpha back to 1. This is a reciprocal animation.
In the docs of UIViewController, we can find:
#property(nonatomic, assign) UIModalTransitionStyle modalTransitionStyle
Set this property to UIModalTransitionStyleCrossDissolve and it will dissolve properly :)
Hope that helps.
I guess, this might be useful for those heroic guys, who still tries to use MPMoviePlayerViewController in full screen mode and with orientation, which differs from the app major one.
I've spent literally a half of working day playing with presenting MPMoviePlayerViewController modally or not modally. But there is no luck with that at all, in sense of transition animation changing. (The modal mode needed for setting orientation which differs from the app major orientation).
I tried presentViewController or presentModalViewController, but the result is the same. No matter what type is the modalTransitionStyle property set, if I do [... dismissViewControllerAnimated:true ...] then default transition style (UIModalTransitionStyleCoverVertical) used anyway. I tested that in iOS 5.1 device and in iOS 6 Simulator.
I haven't tried any other types of controllers... Considering that common controller has method dismissMoviePlayerViewControllerAnimated, I can assume, that this method is used anyway for dismissing a video controller, no matter how did it appear. (Entering transitions didn't work for me as well, except they did not process as CoverVertical (in case of modalTransitionStyle changing).
So, my solution was not use the transition animation at all.
I am sure, Apple had some reasons for allowing only some definite animation for MovieViewController (I really hope so, and that was made not because of "laziness"), but if they wanted some nice experience user would get, they failed, as in my app that's even better when the video appears without any animation (which is worse than CrossDisolving for sure) but that's better than banal CoverVertical.
Looking on that from developer's point of view, it really sounds like they spend much more money for designers to paint nice icons for customers instead of more pleasant and effective work of developers. (
I am brand new to Core Animation, and I need to know how to do 2 animations:
I need to switch XIBs by fading through black (fully releasing the the first view controller)
I need to mimic the UINavigationController's pushViewController animation (switching XIBs and releasing the first view controller)
How can you achieve these animated view transitions?
I've done both of these animations, but maybe not in the exact way you are looking for.
Fade View to black, I took this the other way an instead added a new
subview that covered the entire window that was Black and animated
the Alpha from 0.0 to 1.0. Made for a nice effect.
[UIView animateWithDuration:0.5
animations:^{ _easterEgg.alpha = 1.0; }
completion:^(BOOL finished) { [self animateIndex:0]; }];
Slide in a view like UINavigationController. I didn't do this exactly like UINavigationController since it does multiple animations, but I did have a new view slide the previous view off screen. This code sets the frame of the new view off screen to the right of the current view, builds a frame location that is off the screen to the left, and grabs the current visible frame. Finally it just animates the new view from off screen right into the visible frame, and the old view from the visible frame to off left. Then removes the old view.
CGRect offRight = CGRectMake(_contentView.frame.size.width,
0,
_contentView.frame.size.width,
_contentView.frame.size.height);
CGRect offLeft = CGRectMake(-_contentView.frame.size.width,
0,
_contentView.frame.size.width,
_contentView.frame.size.height);
CGRect visibleFrame = CGRectMake(0, 0, _contentView.frame.size.width, _contentView.frame.size.height);
[view setFrame:offRight];
UIView *currentView = [[_contentView subviews] lastObject];
[_contentView addSubview:view];
[UIView animateWithDuration:0.5
animations:^{
[currentView setFrame:offLeft];
[view setFrame:visibleFrame];
}
completion:^(BOOL finished) {
[currentView removeFromSuperview];
}];