Search code examples
iosipaduisplitviewcontrolleruikeycommand

UISplitviewController and different UIKeyCommands depending on master, detail or both being on screen


I want to include some UIKeyCommands in my app. My app consists of one UISplitViewController that forces the master to be always visible on iPad full screen. On smaller screen it works like it normally would.

Now, I've implemented some UIKeyCommands in the MasterViewController and some in the DetailViewController. However, the app will only show those in DetailViewController. So I put all of them in the RootSplitViewController, but that will show all of them, even when the MasterViewController is hidden in iOS 9's splitview.

What I want though, is for it to show all when the app is fullscreen on iPad and thus the MasterViewController is forced on screen together with the DetailViewController. And when the view is small (ie 50-50) and the MasterViewController is hidden, I want it to only show those of the window that's on screen.

Any ideas on how to achieve this?


Solution

  • In the end I managed to do this - although in a not-so-pretty way.

    The UIKeyCommands are added to the RootSplitViewController.

    - (NSArray *)keyCommands {
        if (self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) {
            return @[
                        [UIKeyCommand keyCommandWithInput:@"r" modifierFlags:UIKeyModifierCommand action:@selector(changeRestaurant:) discoverabilityTitle:@"Change restaurant"],
                        [UIKeyCommand keyCommandWithInput:@"t" modifierFlags:UIKeyModifierCommand action:@selector(changeTable:) discoverabilityTitle:@"Change table"]
                    ];
        } else {
            if (self.masterIsVisible == YES) {
                return @[
                             [UIKeyCommand keyCommandWithInput:@"t" modifierFlags:UIKeyModifierCommand action:@selector(changeRestaurant:) discoverabilityTitle:@"Change restaurant"]
                        ];
            } else {
                return @[
                             [UIKeyCommand keyCommandWithInput:@"t" modifierFlags:UIKeyModifierCommand action:@selector(changeTable:) discoverabilityTitle:@"Change table"]
                        ];
            }
        }
    }
    

    Those methods call the actual methods in the specific UIViewController.

    - (void)changeRestaurant:(id)sender {
        UINavigationController *nav = (UINavigationController *)[self.viewControllers objectAtIndex:0];
        RestaurantController *master = [nav.viewControllers objectAtIndex:0];
        [master changeRestaurant];
    }
    
    - (void)changeTable:(id)sender {
        UINavigationController *nav = (UINavigationController *)[self.viewControllers objectAtIndex:1];
        TableController *detail = [nav.viewControllers objectAtIndex:0];
        [detail changeTable:sender];
    }
    

    In order for this to work I added a BOOL to the UISplitViewController.

    @interface RootSplitViewController : UISplitViewController
    
    @property (nonatomic) BOOL masterIsVisible;
    
    @end
    

    Which is then called in the MasterViewController.

    - (void)viewDidDisappear:(BOOL)animated {
        RootSplitViewController *rootView = (RootSplitViewController *)self.splitViewController;
        rootView.masterIsVisible = NO;
    }
    
    - (void)viewDidAppear:(BOOL)animated {
        RootSplitViewController *rootView = (RootSplitViewController *)self.splitViewController;
        rootView.masterIsVisible = YES;
    }
    

    I know this might not be the pretties method, but it works. If anyone knows a better way to do it, I'd love to hear your feedback.