ios - 如何修改 PKRevealController 滑出式菜单以应对 iOS 7?

标签 ios objective-c cocoa-touch ios7 xcode5

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

该代码适用于 iOS 6,其中状态栏是不透明的,顶部 View 未与状态栏进行 alpha 混合。

但是,例如,在 iOS 7 上,我在我的 .xib 文件中创建了这个 View ,这是它在 iOS 6 模拟器中运行的样子,此处显示的是打开的滑出菜单:

enter image description here

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

enter image description here

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

   [  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 = 。试过没有效果。

我该如何解决这个问题?我读过 Fine Guide由 Apple 发布,它没有提供代码,只有一般指导,如 status bar 上的此页面.

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

调出弹出 View 的代码如下所示:

- (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,我不费心在 apple 系统状态栏下方放置任何 View ,在顶部留下一个黑色栏,这不好,但它表明我正在修改代码中的右侧区域,至少:

- (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];
    }
}

上面的 hack 几乎足够了,如果我也将它添加到 UIViewController+PKRevealController.m:

-(UIStatusBarStyle)preferredStatusBarStyle{
    return UIStatusBarStyleBlackOpaque;
}

上面的代码在添加时会导致以下提示/警告:

Category 正在实现一个方法,该方法也将由其主类实现。

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

我自己修改的 PKRevealController 代码副本,包括上面的 hack,形式略有改进,可在此处找到:https://github.com/wpostma/PKRevealController

最佳答案

我也一直在与 PKRevealController 作斗争。虽然我仍在寻找更好的解决方案,但我会分享我到目前为止的想法。

我的两个问题是:

  1. 状态栏样式始终如一,我希望前 View 和菜单采用不同的样式;
  2. 菜单 View 顶部单元格(它是一个 TableView Controller )出现在状态栏后面。

1。动态状态栏样式

首先,我有自己的 PKRevealController 子类,其中我有一个自定义初始化程序和一些自定义方法,用于将新 View Controller 加载到前 View 导航 View Controller 中。但这与现在无关。

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

- (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 时,显示 Controller 状态仍未更改。为此,请转到设置状态的每个方法,例如enterPresentationModeForRightViewControllerAnimated 并在它调用对帧的任何更改之前设置状态(将触发动画循环)。我在 5 个不同的地方做了。

2。带插图的左/右菜单

对于这个,我不得不说我使用了一种解决方法:我只是在 TableView (tableHeaderView 属性)上设置了一个标题 View 。

将其放入 UITableViewController 的 viewDidLoad 中:

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 中执行。使用 this other answer知道怎么做。

关于ios - 如何修改 PKRevealController 滑出式菜单以应对 iOS 7?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19228603/

相关文章:

cocoa-touch - UIGestureRecognizer阻止表格 View 滚动

ios - 如何在swift5中获取UIButton名称?

ios - 获取从 UITableViewController 中选择的行

iOS7选择按钮边框效果

ios - UIButton 的 Touch Drag/Exit 命中区域的大小有什么问题?

ios - 如何调整异步下载图片的单元格高度

ios - 如果编译时间超过可接受的水平,我可以创建一个失败的单元测试吗?

ios - 如何保持表格 View 滚动以停止重复使用单元格

iphone - Apple/iPhone 开发 IDE 首选项?

ios - 过度拥挤的标签在饼图和条形图中不可读