Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
662 views
in Technique[技术] by (71.8m points)

iphone - Set show/hide for master view enable in UISplitViewController for only one view controller in landscape mode

My App's Root view controller is UISplitViewController. Master and Detail view controllers are two navigation controllers. What I want is, when a particular view controller gets visible in master view, I need master view to be hidden and show-able by swipe gesture. When I implement delegate methods and set presentWithGesture to yes before setting the root view controller, it works as its normal behavior for all the view controllers coming on navigation stack. But I need it only for for one view controller. Please share any idea you have.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I previously accomplished this by triggering a rotation event and implementing the "shouldHideViewController" delegate method. The biggest issue with doing it that way is that it rarely looks good. Sometimes it appears to animate, while others it just hurries off the screen. I wrote the below functions and placed them in my appdelegate to handle hiding/showing the master. It hides with a nice animation and has worked nicely for me so far (note: this is an edit of my preliminary response to this question).

This function Will hide/show masterViewController by adjusting it's frame with an animation. you can also pass a completion block to be called when the animation is finished incase calling controller needs to do animations in-order for it's view to layout nicely. Pass nil if not needed. Note that this also works best when using autolayout.

#pragma mark - UISplitView Hide Master
/** Will hide/show masterViewController by adjusting it's frame with an animation.
 * Can pass a completion block to be called when the animation is finished incase calling
 * controller needs to do animations in-order for view. Pass nil if not needed.
 @param completionBlock - accepts an optional completion block or nil arguement. The completion block is called when the hide/unhide animation is complete.
 @return void
 */
-(void)toggleHideMaster:(void(^)(void))completionBlock
{
    __weak MyAppDelegate  *delegate = self;
    __weak UISplitViewController *splitView = (UISplitViewController*)self.window.rootViewController;

    // Adjust the detailView frame to hide/show the masterview
    [UIView animateWithDuration:0.20f
                          delay:0.0f
                        options:UIViewAnimationOptionCurveEaseInOut
                     animations:^(void)
     {
         CGRect selfFrame = splitView.view.frame;

         // Get the width of the master view controller - so we know how far to animate.
         CGFloat deltaWidth = delegate.masterNavigationController.topViewController.view.frame.size.width;

         if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
         {
             if (!delegate.masterIsHidden)
             {
                selfFrame.size.width += deltaWidth;
                selfFrame.origin.x -= deltaWidth;
             }
             else
             {
                selfFrame.size.width -= deltaWidth;
                selfFrame.origin.x += deltaWidth;
             }
         }
         else
         {
             if(!delegate.masterIsHidden)
             {
                 selfFrame.size.height += deltaWidth;
                 if (splitView.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
                 {
                     selfFrame.origin.y -= deltaWidth;
                 }
             }
             else
             {
                 selfFrame.size.height -= deltaWidth;
                 if (splitView.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
                 {
                     selfFrame.origin.y += deltaWidth;
                 }
             }
         }

         [splitView.view setFrame:selfFrame];
     }completion:^(BOOL finished){
         if (finished)
         {
             delegate.masterIsHidden = !delegate.masterIsHidden;

             if (completionBlock)
             {
                 completionBlock();
             }
         }
     }];
}

/** Method is called by the Navigation controller when the ipad is rotated. Also called when we come from the background incase we were in a full screen state. This is to get the master controller
  back into the correct state.
  @return void
 */
- (void)updateHideMasterOnRotation {
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
        if (self.masterIsHidden) {
            self.masterIsHidden = NO;
            [self toggleHideMaster:nil];
        }
    }
}
// I observe the rotation in my detailview's navigationcontroller like this.
// We track this on the navigation controller to globally reset the master hidden state to where it needs to be. This won't take into account previously passed completion blocks. If needed that can be handled in the view controller implementing the hideable splitview.
// Again - additional things will need to be considered if supporting portrait - like resetting if we rotate to a portrait orientation.
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    MYAppDelegate *appDelegate = (MYAppDelegate*)[UIApplication sharedApplication].delegate;

    [appDelegate updateHideMasterOnRotation];
}

Now you have a pattern that will hide the master view with animation and can be called by any viewcontroller. This example is for an app that is locked in landscape, but supports both landscape rotations (FYI), you could update the pattern to work in portrait with a few conditionals. This also allows a minimalistic approach to this functionality. I have looked at MGSplitviewcontroller before, and while it's wonderful, I don't need all the functionality it provides. I also don't like having dependencies that are dependent on others to update when I don't need most of what they do.

Edit 12/10 - Added iOS8 support to this answer. In iOS7, the xy coords for the splitview's frame were reversed. In iOS8 they are as you would expect. So we now need to take this into account. The frame is also unchanged on rotation in iOS8, so we only update on rotation in iOS < 8.0.

Hope this helps someone out.

Happy Programming.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...