我有一个使用PKRevealController的应用程序,它实现了一个类似于iOS上流行的Facebook和GMAIL应用程序中的滑出菜单。该应用程序是在XCode 5中构建的,可以在iOS 6和iOS 7上运行。我需要弄清楚如何让它在两个地方都能正常工作,所以一个简单的.XIB黑客让它看起来在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,但未在status bar上提供代码,仅提供此页面的一般指导。
很容易复制这个问题,只需克隆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,让我做上述我正在考虑的黑客攻击?
例如,这里是一个非常丑陋的黑客,我不打扰在苹果系统状态栏下放置任何视图,在顶部留下一个黑色条,这是不好的,但它显示我正在修改代码中的右侧区域,至少:
- (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
答案 0 :(得分:1)
我也一直在努力使用PKRevealController。虽然我仍在寻找更好的解决方案,但我将分享到目前为止所提出的建议。
我的两个问题是:
首先,我有自己的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个不同的地方做过。
对于这个,我不得不说我使用了一种解决方法:我只是在表视图(tableHeaderView
属性)上设置了一个标题视图。
将它放在你的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知道如何操作。
答案 1 :(得分:0)
如果您不需要iOS 5-支持,则可以使用autolayout并将最顶层的视图与topLayoutGuide
对齐。
因此,例如,如果你的左视图控制器是一个带有UITableView的UIViewController,你可以将UITableView的上边缘捕捉到topLayoutGuide。
您可以在(1) IB(故事板)或(2)代码中执行此操作。
我个人更喜欢第一种方法,只要它不需要不必要的代码。您只需打开故事板并将表格视图的顶部边缘捕捉到topLayoutGuide。在iOS 7中,您将最终得到topLayoutGuide约束,在iOS6中,topLayoutGuide约束被转换为通用的容器视图常量。
如果您使用第二种方法,则必须确保在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
}