在UISplitViewController中为横向模式中的一个视图控制器设置显示/隐藏主视图启用

时间:2013-09-03 10:34:20

标签: iphone ios objective-c xcode uisplitviewcontroller

My App的Root视图控制器是UISplitViewController。 Master和Detail视图控制器是两个导航控制器。 我想要的是,当一个特定的视图控制器在主视图中可见时,我需要通过滑动手势隐藏和显示主视图。 当我在设置根视图控制器之前实现委托方法并将presentWithGesture设置为yes时,它将作为导航堆栈上所有视图控制器的正常行为。但我只需要一个视图控制器。请分享你的任何想法。

1 个答案:

答案 0 :(得分:2)

我之前通过触发旋转事件并实现“shouldHideViewController”委托方法来完成此操作。这样做的最大问题是它很少看起来很好。有时它似乎有动画,而有些它只是匆匆离开屏幕。我编写了以下函数并将它们放在我的appdelegate中以处理隐藏/显示主控。它隐藏着一个很好的动画,到目前为止对我来说效果很好(注意:这是我对这个问题的初步回答的编辑)。

此功能将通过动画调整其框架来隐藏/显示masterViewController。 您还可以传递一个完成块,以便在动画完成时调用,因为调用控制器需要按顺序执行动画,以便它可以很好地进行布局。如果不需要,通过nil。请注意,使用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];
}

现在你有一个模式可以用动画隐藏主视图,并且可以被任何视图控制器调用。此示例适用于在横向上锁定但支持横向旋转(FYI)的应用程序,您可以使用一些条件更新模式以纵向工作。这也允许对此功能采用简约方法。之前我曾看过MGSplitviewcontroller,虽然很棒,但我并不需要它提供的所有功能。当我不需要他们的大部分工作时,我也不喜欢依赖他人的依赖关系进行更新。

编辑12/10 - 为此答案添加了iOS8支持。在iOS7中,splitview框架的xy坐标被颠倒了。在iOS8中,它们正如您所期望的那样。所以我们现在需要考虑到这一点。在iOS8中,框架在旋转时也保持不变,因此我们仅在iOS中的旋转时更新&lt; 8.0。

希望这可以帮助别人。

快乐编程。