I'm testing around the new iOS 7 custom transition API but i have some troubles with the navigation controller case. I tried a very basic test for the moment with this :
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
[transitionContext completeTransition:YES];
}
As you guessed, this code do nothing except to complete the transition with no animations.
But here's the problem : if it's working normally with present / dismiss a controller, all i see with push and pop methods is a black screen, as if [transitionContext completeTransition:YES] didn't work.
I've set all the delegate properties and delegate methods properly, since this method is called all the time (present, dismiss, push, pop).
Did someone already face this issue ?
Try something more like this, I was having trouble with it as well and this helped make more sense of it
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
// 1. obtain state from the context
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
CGRect finalFrame = [transitionContext finalFrameForViewController:toViewController];
// 2. obtain the container view
UIView *containerView = [transitionContext containerView];
// 3. set initial state
CGRect screenBounds = [[UIScreen mainScreen] bounds]; toViewController.view.frame =
CGRectOffset(finalFrame, 0, screenBounds.size.height);
// 4. add the view
[containerView addSubview:toViewController.view];
// 5. animate
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration animations:^{
toViewController.view.frame = finalFrame;
} completion:^(BOOL finished) {
// 6. inform the context of completion
[transitionContext completeTransition:YES];
}];
}
Source: http://www.raywenderlich.com/forums/viewtopic.php?f=37&t=8851
Related
I am using UIViewControllerTransitioningDelegate to build custom transitions between two view controllers (from a MKMapView) to a custom Camera built on (AVFoundation). Everything goes well until I call the presentViewController and the phone seems to hang for about 1 second (when I log everything out). This even seems to happen when I am transitioning to a much simpler view (I have a view controller that only displays a UITextview and even with that there appears to be about a .4 - .5 second delay before the transition is actually called).
This is currently how I am calling the transition
dispatch_async(dispatch_get_main_queue(), ^{
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
CameraViewController *cvc2 = [sb instantiateViewControllerWithIdentifier:#"Camera"];
cvc2.modalPresentationStyle = UIModalPresentationFullScreen; // Needed for custom animations to work
cvc2.transitioningDelegate = self; //Conforms to the UIViewControllerTransitioningDelegate protocol
[self presentViewController:cvc2 animated:YES completion:nil];
});
Here is my animateTransition method for that call. Very straight forward and currently the view that is presenting this only has a MkMapView on it (no additional views or methods).
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
if (self.type == MapAnimationTypePresent) {//From map to another view
UIView *containerView = [transitionContext containerView];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// Amazing category for iOS 7 compatibility found here - http://stackoverflow.com/a/25193675/2939977
UIView *toView = [toViewController viewForTransitionContext:transitionContext];
UIView *fromView = [fromViewController viewForTransitionContext:transitionContext];
toView.frame = self.view.frame;
fromView.frame = self.view.frame;
//Add 'to' view to the hierarchy
toView.alpha = 0;
[containerView insertSubview:toView aboveSubview:fromView];
[UIView animateWithDuration:.5 animations:^{
toView.alpha = 1;
}completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
Any help is greatly appreciated.
I am using some UIViewControllers contained in a UINavigationController.
One is presented with a push segue from a UIButton on the storyboard, and is then dismissed using a swipe gesture which calls
popViewControllerAnimated
I'm using a UINavigationControllerDelegate to provide a custom object which conforms to UINavigationControllerDelegate. The code for animateTransition is shown below.
My problem is that the first time this runs, the view animates in when presenting, but every time after that, it doesn't animate (it just appears instantly).
Can anyone help?
Thanks!
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
//Get references to the view hierarchy
UIView *containerView = [transitionContext containerView];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
if (self.isPresenting) {
[containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromViewController.view.transform = CGAffineTransformMakeTranslation(-1000, 0);
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
} else if (!self.isPresenting) {
//Add 'to' view to the hierarchy
[containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
//Scale the 'from' view down until it disappears
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
//toViewController.view.transform = CGAffineTransformMakeScale(1.0, 1.0);
fromViewController.view.transform = CGAffineTransformMakeScale(0.01, 0.01);
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
}
I ran into a similar set of issues after upgrading to iOS8. A few things to check:
Make sure to call these before starting the animations:
[toViewController beginAppearanceTransition:YES animated:YES];
[fromViewController beginAppearanceTransition:NO animated:YES];
Then call these in the completion block:
[toViewController endAppearanceTransition];
[fromViewController endAppearanceTransition];
[transitionContext completeTransition:finished];
The above is needed to ensure viewWillAppear: and viewWillDisappear: are called at the right times.
Set modalPresentationStyle = UIModalPresentationFullScreen, instead of UIModalPresentationCustom (which behaves very differently).
Hope this helps.
Cheers!
Be careful setting self.navigationController.delegate
you probably place it in somewhere that only runs once like ViewDidLoad
try placing it in ViewDidAppear
override func viewDidAppear(animated: Bool)
{
super.viewDidAppear(animated)
self.navigationController.delegate = self
}
I want to animate the transitions between the tabs of a UITabBarController. For some reason this method from the UIViewControllerAnimatedTransitioning protocol is called twice:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
The stacktrace:
And immediately after:
Also the - (void)animationEnded:(BOOL)transitionCompleted method is called twice.
I have no ideea why.
This is the code:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
UIView *containerView = [transitionContext containerView];
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
[toVC.view setTransform:CGAffineTransformMakeTranslation(320, 0)];
[containerView addSubview:toVC.view];
[UIView animateWithDuration:0.5 animations:^{
[toVC.view setTransform:CGAffineTransformIdentity];
[fromVC.view setTransform:CGAffineTransformMakeTranslation(-320, 0)];
} completion:^(BOOL finished) {
[fromVC.view setTransform:CGAffineTransformIdentity];
[toVC.view setTransform:CGAffineTransformIdentity];
[transitionContext completeTransition:YES];
}];
}
For a first impression I believe - (void)animationEnded:(BOOL)transitionCompleted is called twice because you call [transitionContext completeTransition:YES] , which based on apple docs:
Call this method after your animations have completed to notify the system that the transition animation is done. The default implementation of this method calls the animator’s animationEnded: method to give it a chance to perform any last minute cleanup.
And if UIViewControllerAnimatedTransitioning is called twice then here you go.
For further analysis of why UIViewControllerAnimatedTransitioning is called twice i would be happy to see your animationControllerForPresentedController and animationControllerForDismissedController implementation.
I'm trying to build a custom transition in iOS 7. The transition occurs fine, but then when transition context complete transition the modal screen disappears from the view entirely. I've followed several tutorials and I don't see what I am doing wrong. In addition, if I don't call "complete transition" then the view stays, but will not receive any touch events. I checked in Reveal App and there is no view sitting on top of it. Any ideas?
Here is the method where I initiate the transition
- (IBAction)settingsButtonClicked:(id)sender
{
UINavigationController *navigationController =[[self storyboard] instantiateViewControllerWithIdentifier:#"SettingsNavigationViewController"];
navigationController.transitioningDelegate = self;
[self presentViewController:navigationController animated:YES completion:nil];
}
Here is the code for the custom transition:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toViewController.view];
CGRect sourceRect = [transitionContext initialFrameForViewController:fromViewController];
CGRect initialTargetFrame = [transitionContext initialFrameForViewController:toViewController];
CGRect initialFrame = CGRectMake(sourceRect.size.width + initialTargetFrame.size.width, 0, initialTargetFrame.size.width, initialTargetFrame.size.height);
CGPoint destinationPoint = CGPointMake(sourceRect.size.width - 500, 0);
CGAffineTransform translate = CGAffineTransformMakeTranslation(initialFrame.origin.x, initialFrame.origin.y);
toViewController.view.transform = translate;
[UIView animateWithDuration:PRESENT_DURATION delay:0 options:UIViewAnimationOptionCurveEaseOut
animations:^{
toViewController.view.transform = CGAffineTransformMakeTranslation(destinationPoint.x, destinationPoint.y);
}
completion:^(BOOL completed) {
if (completed) {
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
}
}];
}
So I found out what I was doing wrong. I was changing the modalPresentationStyle to custom on the view controller that was being popped onto the navigation controller when I should have been setting it on the navigation controller itself. I added this line to the settingsButtonClicked method above and it worked properly.
navigationController.modalPresentationStyle = UIModalPresentationCustom;
i'm using iOS 7 Custom transition to present a UINavigationController.
but there is a problem. while its animating, the size of navigation bar is only 44points. then after done animating, navigation controllers figured out there is a status bar, so its added 20points for status bar.
my question is, is there possible to set navigation bar to 64point when its animating, so it doesn't change anymore when its done animating.
please see it here for more detail Custom View Transitions
This is my custom animation code:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
CGRect finalFrame = [transitionContext finalFrameForViewController:toViewController];
UIView *containerView = [transitionContext containerView];
CGRect screenBounds = [[UIScreen mainScreen] bounds];
toViewController.view.frame = CGRectOffset(finalFrame, 0, screenBounds.size.height);
[containerView addSubview:toViewController.view];
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
toViewController.view.frame = finalFrame;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
UPDATE: somebody fixed this problem. but pretty hacky.
add this code after added toViewController.view to containerView.
if ([toViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*) toViewController;
UINavigationBar* bar = navigationController.navigationBar;
CGRect frame = bar.frame;
bar.frame = CGRectMake(frame.origin.x, frame.origin.y + 20.0f, frame.size.width, frame.size.height);
}
is there a better way to do it?
I had the same problem, and solved adding the toViewController to container before I set this frame.
Invert the lines like as follow:
[containerView addSubview:toViewController.view];
toViewController.view.frame = CGRectOffset(finalFrame, 0, screenBounds.size.height);