当UIViewController推送时显示UITabBar

kom*_*cha 9 iphone show uinavigationcontroller uitabbar drilldown

这是我的情况:
我有一个UINavigationController内部UITabBarController.当我向下钻取导航控制器时,在某些时候我必须隐藏它,UITabBar因为我希望视图具有尽可能多的空间.
我通过self.hidesBottomBarWhenPushed = YES在推动内部使用来做到这一点UIViewController,并且它工作得很好.
但是,我想UITabBar在后面推出的控制器中显示后面的内容.我试图放入self.hidesBottomBarWhenPushed = NO其他控制器,但UITabBar不会回来.

文档说明似乎是正常的:

hidesBottomBarWhenPushed

If YES, the bar at the bottom of the screen is hidden; otherwise, NO. If YES, the bottom bar remains hidden until the view controller is popped from the stack.

实际上,当弹出具有此属性设置为yes的控制器时,tabbar会返回.

UITabBar一旦它被隐藏了,是否有任何正确的方法来显示控制器被推动的时间?

提前致谢

Ami*_*itP 13

不推荐使用hidesBottomBarWhenPushed.我发现使用以下方法实现隐藏并显示UITabBar非常简单:

self.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
self.hidesBottomBarWhenPushed = NO;
Run Code Online (Sandbox Code Playgroud)

因此,在推送detailViewConroller之后,您应该将hide属性重置为NO.这样,当细节视图弹出时,它将再次出现.在viewWillApear/disapear等中无需任何其他更改.享受.


MHC*_*MHC 7

好的,我们还有很长的路要走.

当您从文档中读取时,默认行为是明确的:一旦视图控制器的hides...属性为YES,标签栏将被隐藏,直到弹出视图控制器.你想要的是什么直接与此相矛盾,并且出于各种原因,我首先建议不采取这种方法.

但是,这并不意味着无法实施.


  • hides...属性设置回NO

您无法修改默认行为.要显示选项卡栏,堆栈中的所有视图控制器必须将其hides...属性设置为NO.因此,从隐藏标签栏的视图中,如果要在按下新视图时再次显示该栏,则必须再次将之前的视图控制器hides...属性设置为NO.

在推送新视图控制器之前,将属性设置回NO.

// ... prepare viewControllerToPush

self.hidesBottomBarWhenPushed = NO;
[self.navigationController pushViewController:viewControllerToPush animated:YES];
[viewControllerToPush release];
Run Code Online (Sandbox Code Playgroud)

通过这样做,您将再次拥有标签栏.但是,您将识别从左侧推入标签栏,而从右侧推入新视图.这显然是不可取的,所以我们需要解决这个问题.


  • 覆盖选项卡栏的图层操作

问题是,标签栏再次出现时使用的默认图层操作(动画)是左侧的推送过渡动画.UITabBar实现的- (id < CAAction >)actionForLayer:(CALayer *)layer forKey:(NSString *)key方法告诉我使用左边的动画作为案例.我们需要覆盖此方法,以便从右侧返回动画.

为了显示标签栏,Cocoa修改了它的图层position属性.因此,我们的新方法应该从右侧为键返回动画position,对于所有其他键,它应该使用默认实现.请注意,positionApple未记录用于标签栏的内容,因此在以下版本中如有更改,恕不另行通知.无论如何,我们正在实施一些与苹果规范直接相悖的东西,因此不能抱怨太多.

但是,您不能只使用子类来覆盖该方法.因为即使您有UITabBar的自定义子类,也无法修改UITabBarController类以使用它而不是默认的UITabBar.

所以,它变得有点复杂.为了将自己的逻辑植入UITabBar类,您必须"交换"消息的实现actionForLayer: forKey:.

首先,使用category为UITabBar类添加一个新方法.

@interface UITabBar(customAction)
@end

@implementation UITabBar(customAction)

- (id < CAAction >)customActionForLayer:(CALayer *)layer forKey:(NSString *)key {
    if ([key isEqualToString:@"position"]) {
        CATransition *pushFromRight = [[CATransition alloc] init];
        pushFromRight.duration = 0.25; 
        pushFromRight.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; 
        pushFromRight.type = kCATransitionPush; 
        pushFromRight.subtype = kCATransitionFromRight;
        return [pushFromRight autorelease];
    } 
return [self defaultActionForLayer:layer forKey:key];
}
@end
Run Code Online (Sandbox Code Playgroud)

viewDidAppear标签栏控制器的方法中,插入以下代码.

Method original = class_getInstanceMethod([UITabBar class], @selector(actionForLayer:forKey:));
Method custom = class_getInstanceMethod([UITabBar class], @selector(customActionForLayer:forKey:));

class_replaceMethod([UITabBar class], @selector(actionForLayer:forKey:), method_getImplementation(custom), method_getTypeEncoding(custom));
class_addMethod([UITabBar class], @selector(defaultActionForLayer:forKey:), method_getImplementation(original), method_getTypeEncoding(original));
Run Code Online (Sandbox Code Playgroud)

您希望这样做viewDidAppear而不是viewDidLoad,因为否则标签栏将在应用程序第一次显示时从右侧滑入.

现在,当UITabBar实例获取消息时actionsForLayer forKey:,将customActionForLayer forKey:调用自定义方法.它拦截键position,并从右侧返回一个动画.如果它是另一个密钥,它将调用消息的原始实现,该消息现在已连接到消息defaultActionsForLayer forKey:.


好的,我们有.请记住,当弹出视图时,您可能必须将hides...属性设置回YES,因为在推送新视图时将其设置为NO(并执行一些类似的技巧来正确设置它的动画).

我花了一些时间在这上面但具有讽刺意味的是,我不得不说*不要再使用它了,因为它使用了Cocoa类的未记录信息(标签栏动画的"位置"键),与记录的行为相矛盾,并且反对Apple的人机界面指南.您可能会发现您的应用程序与以下SDK版本不同,用户无法轻松采用该界面,甚至Apple拒绝您在App Store上的应用程序.

那我的答案到底是什么?好吧,我猜想一个关于iOS开发的一些有趣话题的例子(以及证明我今天非常无效的证据:P).


Mic*_*iel 5

这是在iOS 5中使用情节提要时的解决方法:

在执行强制搜索之前将hidesBottomBarWhenPushed属性设置为NO

- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
   if( [segue.identifier isEqualToString:@"PushDetailView"] )
   {
      self.hidesBottomBarWhenPushed = NO;
   }

   [super prepareForSegue:segue sender:sender];
}
Run Code Online (Sandbox Code Playgroud)

segue标识符显然由您决定。

YES当视图控制器的视图消失时,将其立即设置回:

- (void)viewWillDisappear:(BOOL)animated
{
   self.hidesBottomBarWhenPushed = YES;

   [super viewWillDisappear:animated];
}
Run Code Online (Sandbox Code Playgroud)

使用的所有正确动画,就像超级魅力一样(在iOS 5.1上经过测试)UITabBar