1

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

4

1 回答 1

2

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

此函数将通过使用动画调整它的框架来隐藏/显示 masterViewController。您还可以传递一个完成块以在动画完成时调用,以防调用控制器需要执行动画以使其视图布局良好。如果不需要,则传递 nil。请注意,这在使用自动布局时也最有效。

#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 < 8.0 中更新旋转。

希望这可以帮助某人。

快乐编程。

于 2013-12-09T23:55:56.593 回答