2

我有一个使用PKRevealController的应用程序,它实现了一个滑出菜单,类似于 iOS 上流行的 Facebook 和 GMAIL 应用程序中的菜单。该应用程序是在 XCode 5 中构建的,并在 iOS 6 和 iOS 7 上运行。我需要弄清楚如何让它在这两个地方都正常工作,所以一个简单的 .XIB hack 让它在 iOS 7 中看起来不错,但让它看起来在 iOS 6 中更糟糕的是不行。

该代码适用于 iOS 6,其中状态栏是不透明的,并且顶部视图没有与状态栏混合 alpha。

但是,例如,在 iOS 7 上,我在我的 .xib 文件中创建了这个视图,下面是它在 ios 6 模拟器中运行时的显示方式,此处显示的是打开滑出菜单:

在此处输入图像描述

在 ios 7 上运行的相同 .xib 文件,当滑出菜单打开时,滑出菜单的 .xib 内容的顶部现在位于状态栏下方,正如 Apple 在其 ios 7 过渡指南中所说的那样:

在此处输入图像描述

我需要在 PKRevealController 中修改的类可能是正在创建和呈现包含视图的呈现视图控制器PKRevealControllerContainerView,我认为包含的视图被称为。我想我可能需要像这样创建某种视图层次结构:

   [  Outermost View container 
        [ some kind of blob to occupy the header area ]
        [ the client view I want to appear the way it did in iOS 6]
   ]

我一直在阅读,可能有更简单的方法,但我不太了解它们,比如向我的 info.plist 添加属性的方法,比如View controller-based status bar appearance= YES。我试过它没有达到预期的效果。

我该如何解决这个问题?我已经阅读了Apple 发布的Fine Guide,它没有提供代码,只有像状态栏上的这个页面这样的一般指导。

复制这个问题很容易,只需克隆 git repo https://github.com/pkluz/PKRevealController,构建并运行。

弹出弹出视图的代码如下所示:

- (void)addLeftViewControllerToHierarchy
{
    if (self.leftViewController != nil && ![self.childViewControllers containsObject:self.leftViewController])
    {
        [self addChildViewController:self.leftViewController];
        self.leftViewContainer.viewController = self.leftViewController;

        if (self.leftViewContainer == nil)
        {
            self.leftViewContainer = [[PKRevealControllerContainerView alloc] initForController:self.leftViewController shadow:NO];
            self.leftViewContainer.autoresizingMask = [self autoresizingMaskForLeftViewContainer];
        }

        self.leftViewContainer.frame = [self leftViewFrame];
        [self.view insertSubview:self.leftViewContainer belowSubview:self.frontViewContainer];
        [self.leftViewController didMoveToParentViewController:self];
    }
}

上面是由 PKRevealController.m 调用的,如下所示:

- (void)showLeftViewControllerAnimated:(BOOL)animated
                            completion:(PKDefaultCompletionHandler)completion
{
    __weak PKRevealController *weakSelf = self;

    void (^showLeftViewBlock)(BOOL finished) = ^(BOOL finished)
    {
        [weakSelf removeRightViewControllerFromHierarchy];
        [weakSelf addLeftViewControllerToHierarchy];  // HELLO LEFT Slide-out menu.

        ....

有比我的想法更好的方法吗?Apple 是否提供了某种方法来简化此操作,或者尝试在单个代码库中支持 iOS 6 和 iOS 7 是否让我做上述我正在考虑的黑客行为?

例如,这里是一个非常丑陋的 hack,我不费心在苹果系统状态栏下方放置任何视图,在顶部留下一个黑条,这不好,但它表明我正在修改正确的区域代码,至少:

- (void)addLeftViewControllerToHierarchy
{
    CGRect   lvFrame;

    if (self.leftViewController != nil && ![self.childViewControllers containsObject:self.leftViewController])
    {
        [self addChildViewController:self.leftViewController];
        self.leftViewContainer.viewController = self.leftViewController;

        if (self.leftViewContainer == nil)
        {
            self.leftViewContainer = [[PKRevealControllerContainerView alloc] initForController:self.leftViewController shadow:NO];
            self.leftViewContainer.autoresizingMask = [self autoresizingMaskForLeftViewContainer];
        }

        lvFrame = [self leftViewFrame];
        lvFrame.origin.y += 20; // ugly hack demo code only! don't really do it this badly!
        lvFrame.size.height -= 20;
        self.leftViewContainer.frame = lvFrame;
        [self.view insertSubview:self.leftViewContainer belowSubview:self.frontViewContainer];
        [self.leftViewController didMoveToParentViewController:self];
    }
}

如果我还将其添加到UIViewController+PKRevealController.m

-(UIStatusBarStyle)preferredStatusBarStyle{
    return UIStatusBarStyleBlackOpaque;
}

添加上述代码时,会导致以下提示/警告:

Category is implementing a method that will also be implemented by its primary class.

我将上述注释包括在内以展示我的尝试,我欢迎了解真正的专家是如何做到这一点的。

我自己修改的 PKRevealController 代码副本,包括上面的 hack,以稍微改进的形式,可以在这里找到: https://github.com/wpostma/PKRevealController

4

2 回答 2

1

我也一直在为 PKRevealController 苦苦挣扎。虽然我仍在寻找更好的解决方案,但我将分享我到现在为止的想法。

我的两个问题是:

  1. 状态栏样式始终相同,我希望前视图和菜单的样式不同;
  2. 菜单视图顶部单元格(它是一个表格视图控制器)显示在状态栏后面。

1.动态状态栏样式

首先,我有自己的 PKRevealController 子类,其中我有一个自定义初始化程序和一些自定义方法来将新视图控制器加载到前视图导航视图控制器中。但这暂时无关紧要。

我使用这个子类来实现preferredStatusBarStyle如下,以便显示控制器可以为每个状态提供正确的样式:

- (UIStatusBarStyle)preferredStatusBarStyle {
    switch (self.state) {
        case PKRevealControllerFocusesLeftViewController:
            return [self.leftViewController preferredStatusBarStyle];
            break;
        case PKRevealControllerFocusesRightViewController:
            return [self.rightViewController preferredStatusBarStyle];
            break;
        case PKRevealControllerFocusesFrontViewController:
            return [self.frontViewController preferredStatusBarStyle];
            break;
        case PKRevealControllerFocusesLeftViewControllerInPresentationMode:
            return [self.leftViewController preferredStatusBarStyle];
            break;
        case PKRevealControllerFocusesRightViewControllerInPresentationMode:
            return [self.rightViewController preferredStatusBarStyle];
            break;

        default:
            return UIStatusBarStyleDefault;
            break;
    }
}

然而,仅此一项是行不通的。还是要说状态栏样式需要用setNeedsStatusBarAppearanceUpdate. 正如 Apple 所说,这应该从动画循环内部调用,您可以在 PKRevealController 的setFrontViewFrameLinearly方法中找到一个。这是我修改后的样子:

- (void)setFrontViewFrameLinearly:(CGRect)frame
                         animated:(BOOL)animated
                         duration:(CGFloat)duration
                          options:(UIViewAnimationOptions)options
                       completion:(PKDefaultCompletionHandler)completion
{
    [UIView animateWithDuration:duration delay:0.0f options:options animations:^
    {
        self.frontViewContainer.frame = frame;
        if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending) {
            [self setNeedsStatusBarAppearanceUpdate];
        }
    }
    completion:^(BOOL finished)
    {
        safelyExecuteCompletionBlockOnMainThread(completion, finished);
    }];
}

如果你在这一点上尝试一下,风格会混淆。您可以很快得出结论,到preferredStatusBarStyle调用显示控制器时,状态仍然没有改变。为此,请转到设置状态的每个方法,例如enterPresentationModeForRightViewControllerAnimated,在它调用对帧的任何更改之前设置状态(将触发动画循环)。我在5个不同的地方做了。

2. 带插图的左/右菜单

对于这个我不得不说我使用了一种解决方法:我刚刚在表格视图(tableHeaderView属性)上设置了一个标题视图。

把它放在viewDidLoad你的 UITableViewController 中:

UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0.f, 0.f, self.tableView.frame.size.width, 20.f)];
headerView.backgroundColor = [UIColor whiteColor];

self.tableView.tableHeaderView = headerView;

不要忘记添加一些条件,这样它就不会在 iOS 6 中执行。使用这个其他答案来了解如何去做。

于 2013-10-11T09:59:25.080 回答
0

如果您不需要 iOS 5 支持,您可以使用自动布局并将最上面的视图对齐到topLayoutGuide.

iOS6 IOS 7


因此,例如,如果您的左视图控制器是一个带有 UITableView 的 UIViewController,您可以将 UITableView 的顶部边缘捕捉到 topLayoutGuide。您可以在(1) IB(故事板)或(2)从代码中执行此操作。

我个人更喜欢第一种方法,因为它不需要不必要的代码。您只需打开故事板并将表格视图的顶部边缘捕捉到 topLayoutGuide。在 iOS 7 中你会得到 topLayoutGuide 约束,在 iOS6 中 topLayoutGuide 约束被转换为一个通用的容器视图常量。

IB方式

如果您使用第二种方法,则必须确保在 iOS6 中不使用 topLayoutGuide,如下所示:

// assume you'r in your UIViewController subclass
if (![self respondsToSelector:@selector(topLayoutGuide)]) 
{
    // topLayoutGuide is not supported, probably iOS6
    // add constraints to snap tableview's top edge to superview's top edge
}
else
{
    // cool, topLayoutGuide is supported, probably iOS7
    // add constraints to snap tableview's top edge to topLayoutGuide
}
于 2014-02-13T09:37:57.100 回答