Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to suppress the Master-Detail Controller swipe gesture, and recreate its behaviour on iOS 7

By default the UISplitViewController provides a swipe gesture to open the master view in portrait mode.

Unfortunately, this gesture opens the master controller even when manipulating sliders on the detail page! I discovered another question on here where this was marked as a bug reported for iOS 5.1, and yet the problem persists on iOS7...

Is there now a way to suppress this gesture under these circumstances? I realise that I can remove it completely by doing this:

splitViewController.presentsWithGesture = NO;

However it would be nice to allow the gesture and still have usable sliders!

like image 498
tarmes Avatar asked Oct 14 '13 09:10

tarmes


1 Answers

After experimenting I wondered what would happen if I attempted to create my own swipe gesture to open the master view. This works perfectly, and it doesn't fail when using sliders!

So, in the app delegate I suppress the default swipe gesture:

splitViewController.presentsWithGesture = NO;

When the detail view is loaded, I create a swipe gesture:

- (void)viewDidLoad
{
    [super viewDidLoad];

    UISwipeGestureRecognizer *swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleRightSwipe:)];
    swipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
    [self.view addGestureRecognizer:swipeGestureRecognizer];

    [self configureView];
}

In splitViewController:willHideViewController:withBarButtonItem:forPopoverController: I store the references that I need to open the master view myself:

- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
    // Add the bar item to the navigation bar

    barButtonItem.title = NSLocalizedString(@"Master", @"Master");
    [self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];

    // Store references to the button and popover controller so that we can manually open the view using a custome swipe gesture

    self.masterPopoverButton = barButtonItem;
    self.masterPopoverController = popoverController;
}

Finally, I handle the swipe:

- (void)handleRightSwipe:(UISwipeGestureRecognizer *)recognizer {

    // Find the root controller in the stack (this is the one that's also the split view's delegate, and thus has access
    // to the pop over controller.

    MyDetailViewController *rootController = (MyDetailViewController *)[self.navigationController.viewControllers objectAtIndex:0];

    if (!rootController.masterPopoverController.popoverVisible) {

        [rootController.masterPopoverController presentPopoverFromBarButtonItem:rootController.masterPopoverButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
    }
}

This slides in the master view controller. I was concerned that this would display the controller as a traditional popover (with arrows etc), but it actually does the right thing (at least it does under iOS 7 - I haven't tested earlier versions).

Notice that you'll need to create this gesture for each view that you push onto the navigation controller's stack. In my case it's always the same view, so that simplifies things. In other cases it might be a good idea to create a subclass of UIViewController that creates this gesture and handles it, and then use that as a super class for any controllers that are pushed on...

like image 90
tarmes Avatar answered Sep 20 '22 04:09

tarmes