The view controller does not automatically rotate after canceling the interactive firing transition for the presented view controller

I have a presentation controller representing another presentation controller with modalPresentationStyle = UIModalPresentationCustom . Everything is set up so that part of the presentation of the presentation of the presentation of the presentation is displayed below the presented view of the view controller. In this state, the view controller of the view still performs automatic rotation correctly, and I handle the rotation for the presented view controller with automatic shutdown.

Now I'm trying to implement the interactive rejection of the presented view controller using the API to go to the iOS 7 user view. This works, except that when the interactive dismissal is canceled, the auto-rotation processing stops working. (It works again after the presented view controller is fired later.) Why is this happening, and how can I fix it?

EDIT . Here is the code you can run to demonstrate the problem. The view appears from below, and you can drop it by pulling it out. If you cancel the dismissal without missing it completely, the view controller view stops responding to rotations, and the presented view controller view has a corrupted layout.

EDIT . Here is the link to the code below as an Xcode project: https://drive.google.com/file/d/0BwcBqUuDfCG2YlhVWE1QekhUWlk/edit?usp=sharing

Sorry for the massive code reset, but I don't know what I'm doing wrong. Here's a sketch of what is happening: ViewController1 represents ViewController2 . ViewController1 implements UIViewControllerTransitioningDelegate , so it returns animated / interactive controllers for transitions. ViewController2 has a gesture recognizer that controls interactive firing; it implements UIViewControllerInteractiveTransitioning for use as an interactive controller for firing. It also holds a link to the firing animation controller to complete the transition if the user drags the view too much. Finally, there are two animation controller objects. PresentAnimationController sets auto-detection limits for cornering for the presented view controller view, and DismissAnimationController completes the dismissal.

ViewController1.h

 #import <UIKit/UIKit.h> @interface ViewController1 : UIViewController <UIViewControllerTransitioningDelegate> @end 

ViewController1.m

 #import "ViewController1.h" #import "ViewController2.h" #import "PresentAnimationController.h" #import "DismissAnimationController.h" @implementation ViewController1 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = @"View 1"; self.navigationItem.prompt = @"Press "Present" and then swipe down to dismiss."; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Present" style:UIBarButtonItemStylePlain target:self action:@selector(pressedPresentButton:)]; } return self; } - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; // Some subview just to check if layout is working. UIView * someSubview = [[UIView alloc] initWithFrame:self.view.bounds]; someSubview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; someSubview.backgroundColor = [UIColor orangeColor]; someSubview.layer.borderColor = [UIColor redColor].CGColor; someSubview.layer.borderWidth = 2; [self.view addSubview:someSubview]; } // -------------------- - (void)pressedPresentButton:(id)sender { ViewController2 * presentedVC = [[ViewController2 alloc] initWithNibName:nil bundle:nil]; presentedVC.modalPresentationStyle = UIModalPresentationCustom; presentedVC.transitioningDelegate = self; [self presentViewController:presentedVC animated:YES completion:nil]; } // -------------------- // View Controller Transitioning Delegate Methods. - (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { return [[PresentAnimationController alloc] init];; } - (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed { DismissAnimationController * animationController = [[DismissAnimationController alloc] init]; ViewController2 * presentedVC = (ViewController2 *)self.presentedViewController; if (presentedVC.dismissalIsInteractive) { presentedVC.dismissAnimationController = animationController; } return animationController; } - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator { return nil; } - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator { ViewController2 * presentedVC = (ViewController2 *)self.presentedViewController; if (presentedVC.dismissalIsInteractive) { return presentedVC; } else { return nil; } } @end 

ViewController2.h

 #import <UIKit/UIKit.h> #import "DismissAnimationController.h" @interface ViewController2 : UIViewController <UIViewControllerInteractiveTransitioning> @property (weak, nonatomic) UIView * contentView; @property (nonatomic, readonly) BOOL dismissalIsInteractive; @property (strong, nonatomic) DismissAnimationController * dismissAnimationController; @end 

ViewController2.m

 #import "ViewController2.h" @interface ViewController2 () @property (strong, nonatomic) id<UIViewControllerContextTransitioning> transitionContext; @end @implementation ViewController2 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { _dismissalIsInteractive = NO; } return self; } - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5]; // Set up content view. CGRect frame = UIEdgeInsetsInsetRect(self.view.bounds, UIEdgeInsetsMake(15, 15, 15, 15)); UIView * contentView = [[UIView alloc] initWithFrame:frame]; self.contentView = contentView; contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; contentView.backgroundColor = [UIColor cyanColor]; contentView.layer.borderColor = [UIColor blueColor].CGColor; contentView.layer.borderWidth = 2; [self.view addSubview:contentView]; // Set up pan dismissal gesture recognizer. UIPanGestureRecognizer * panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dismissalPan:)]; [self.view addGestureRecognizer:panGesture]; } // -------------------- - (void)dismissalPan:(UIPanGestureRecognizer *)panGesture { switch (panGesture.state) { case UIGestureRecognizerStateBegan: { _dismissalIsInteractive = YES; [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; break; } case UIGestureRecognizerStateChanged: { CGPoint translation = [panGesture translationInView:self.view]; CGFloat percent; if (translation.y > 0) { percent = translation.y / self.view.bounds.size.height; percent = MIN(percent, 1.0); } else { percent = 0; } // Swiping content view down. CGPoint center; center.x = CGRectGetMidX(self.view.bounds); center.y = CGRectGetMidY(self.view.bounds); if (translation.y > 0) { center.y += translation.y; // Only allow swiping down. } self.contentView.center = center; self.view.backgroundColor = [UIColor colorWithWhite:0 alpha:(0.5 * (1.0 - percent))]; [self.transitionContext updateInteractiveTransition:percent]; break; } case UIGestureRecognizerStateEnded: // Fall through. case UIGestureRecognizerStateCancelled: { _dismissalIsInteractive = NO; id<UIViewControllerContextTransitioning> transitionContext = self.transitionContext; self.transitionContext = nil; DismissAnimationController * dismissAnimationController = self.dismissAnimationController; self.dismissAnimationController = nil; CGPoint translation = [panGesture translationInView:self.view]; if (translation.y > 100) { // Complete dismissal. [dismissAnimationController animateTransition:transitionContext]; } else { // Cancel dismissal. void (^animations)() = ^() { CGPoint center; center.x = CGRectGetMidX(self.view.bounds); center.y = CGRectGetMidY(self.view.bounds); self.contentView.center = center; self.view.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5]; }; void (^completion)(BOOL) = ^(BOOL finished) { [transitionContext cancelInteractiveTransition]; [transitionContext completeTransition:NO]; }; [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:animations completion:completion]; } break; } default: { break; } } } // -------------------- // View Controller Interactive Transitioning Methods. - (void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)transitionContext { self.transitionContext = transitionContext; } @end 

PresentAnimationController.h

 #import <Foundation/Foundation.h> @interface PresentAnimationController : NSObject <UIViewControllerAnimatedTransitioning> @end 

PresentAnimationController.m

 #import "PresentAnimationController.h" #import "ViewController2.h" @implementation PresentAnimationController - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext { UIViewController * fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; ViewController2 * toVC = (ViewController2 *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView * containerView = [transitionContext containerView]; CGPoint toCenter = fromVC.view.center; CGRect toBounds = fromVC.view.bounds; toVC.view.center = toCenter; toVC.view.bounds = toBounds; [toVC.view layoutIfNeeded]; [containerView addSubview:fromVC.view]; [containerView addSubview:toVC.view]; CGRect contentViewEndFrame = toVC.contentView.frame; CGRect contentViewStartFrame = contentViewEndFrame; contentViewStartFrame.origin.y += contentViewStartFrame.size.height; toVC.contentView.frame = contentViewStartFrame; UIColor * endBackgroundColor = toVC.view.backgroundColor; toVC.view.backgroundColor = [UIColor clearColor]; void (^animations)() = ^() { toVC.contentView.frame = contentViewEndFrame; toVC.view.backgroundColor = endBackgroundColor; }; void (^completion)(BOOL) = ^(BOOL finished) { toVC.view.autoresizingMask = UIViewAutoresizingNone; toVC.view.translatesAutoresizingMaskIntoConstraints = NO; NSLayoutConstraint * centerXConstraint = [NSLayoutConstraint constraintWithItem:toVC.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:fromVC.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]; NSLayoutConstraint * centerYConstraint = [NSLayoutConstraint constraintWithItem:toVC.view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:fromVC.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; NSLayoutConstraint * widthConstraint = [NSLayoutConstraint constraintWithItem:toVC.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:fromVC.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0]; NSLayoutConstraint * heightConstraint = [NSLayoutConstraint constraintWithItem:toVC.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:fromVC.view attribute:NSLayoutAttributeHeight multiplier:1 constant:0]; [containerView addConstraint:centerXConstraint]; [containerView addConstraint:centerYConstraint]; [containerView addConstraint:widthConstraint]; [containerView addConstraint:heightConstraint]; [transitionContext completeTransition:YES]; }; [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:animations completion:completion]; } - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5; } @end 

DismissAnimationController.h

 #import <Foundation/Foundation.h> @interface DismissAnimationController : NSObject <UIViewControllerAnimatedTransitioning> @end 

DismissAnimationController.m

 #import "DismissAnimationController.h" #import "ViewController2.h" @implementation DismissAnimationController - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext { ViewController2 * fromVC = (ViewController2 *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController * toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView * containerView = [transitionContext containerView]; [containerView addSubview:toVC.view]; [containerView addSubview:fromVC.view]; void (^animations)() = ^() { CGRect contentViewEndFrame = fromVC.contentView.frame; contentViewEndFrame.origin.y = CGRectGetMaxY(fromVC.view.bounds) + 15; fromVC.contentView.frame = contentViewEndFrame; fromVC.view.backgroundColor = [UIColor clearColor]; }; void (^completion)(BOOL) = ^(BOOL finished) { if ([transitionContext isInteractive]) { [transitionContext finishInteractiveTransition]; } [transitionContext completeTransition:YES]; }; [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:animations completion:completion]; } - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5; } @end 

AppDelegate.m

 #import "AppDelegate.h" #import "ViewController1.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; ViewController1 * vc = [[ViewController1 alloc] initWithNibName:nil bundle:nil]; UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:vc]; self.window.rootViewController = nav; [self.window makeKeyAndVisible]; return YES; } @end 
+8
ios iphone uiviewcontroller ios7
source share
1 answer

I think I found your problem. in PresentAnimationController.m, specify toVC.view.translatesAutoresizingMaskIntoConstraints = NO; , and you set all your restrictions in the completion block that you set to - (void)animateTransition:

Comment that the string and all restrictions and addConstraint: calls, and it should work

EDIT:

I just saw that it worked only when the gesture was canceled, and not when the view was initially displayed. Comment everything in the completion block except

[transitionContext completeTransition:YES];

+3
source share

All Articles