kevin-lyn / STPopup

STPopup provides STPopupController, which works just like UINavigationController in popup style, for both iPhone and iPad. It's written in Objective-C and compatible with Swift.
MIT License
2.6k stars 345 forks source link

Adding gesture recognizer to dismiss on background tap will cause dismissal if popup is tapped during a transition #63

Closed tylerjames closed 8 years ago

tylerjames commented 8 years ago

Sorry, that was hard to say concisely in title.

If you add a gesture recognizer to the background as described in the readme like this:

Dismiss popup when tapping background popupController = [[STPopupController alloc] initWithRootViewController:self]; [popupController.backgroundView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(backgroundViewDidTap)]];

the view can be dismissed by tapping anywhere during a transition. It appears that the animation when pushing a new controller is letting taps on the popup interface make it to the background and trigger the gesture recognizer. So if you add the recognizer, push a new view, and then tap somewhere on that view the whole popup will dismiss.

I suppose a remedy would be to add and remove the recognizer when transitioning, but you'd have to do it on every subsequent controller in the nav hierarchy, which would be kind of annoying.

tylerjames commented 8 years ago

Okay, I have a possible solution.

In - (void)transitFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController animated:(BOOL)animated there is a line that disables user interaction on the content view before the animation starts, and then enables it again in the completion handler for the animation. If you do something similar with the _backgroundView then it will prevent the gesture recognizer from being called if the user taps during a transition.

    if (animated) {
    // Capture view in "fromViewController" to avoid "viewWillAppear" and "viewDidAppear" being called.
    UIGraphicsBeginImageContextWithOptions(fromViewController.view.bounds.size, NO, [UIScreen mainScreen].scale);
    [fromViewController.view drawViewHierarchyInRect:fromViewController.view.bounds afterScreenUpdates:NO];

    UIImageView *capturedView = [[UIImageView alloc] initWithImage:UIGraphicsGetImageFromCurrentImageContext()];

    UIGraphicsEndImageContext();

    capturedView.frame = CGRectMake(_contentView.frame.origin.x, _contentView.frame.origin.y, fromViewController.view.bounds.size.width, fromViewController.view.bounds.size.height);
    [_containerView insertSubview:capturedView atIndex:0];

    [fromViewController.view removeFromSuperview];

    _backgroundView.userInteractionEnabled = NO;
    _containerView.userInteractionEnabled = NO;
    toViewController.view.alpha = 0;
    [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
        [self layoutContainerView];
        [_contentView addSubview:toViewController.view];
        capturedView.alpha = 0;
        toViewController.view.alpha = 1;
        [_containerViewController setNeedsStatusBarAppearanceUpdate];
    } completion:^(BOOL finished) {
        [capturedView removeFromSuperview];
        [fromViewController removeFromParentViewController];

        _backgroundView.userInteractionEnabled = YES;
        _containerView.userInteractionEnabled = YES;
        [toViewController didMoveToParentViewController:_containerViewController];

        [fromViewController endAppearanceTransition];
        [toViewController endAppearanceTransition];
    }];
    [self updateNavigationBarAniamted:animated];
}

That's the block of code that I'm referring to. See where I've added _backgroundView.userInteractionEnabled = NO; before the animation kicks off and then a corresponding _backgroundView.userInteractionEnabled = YES; in the completion handler.

Seems to fix the problem, and I'm not aware of any adverse side effects, though I'm admittedly not intimately familiar with the code.

kevin-lyn commented 8 years ago

@tylerjames I've pushed a fix for this. You may need to point to the latest commit if you are using Pod.