10

这是我的情况:
我有UINavigationController一个UITabBarController. 当我向下钻取导航控制器时,有时我必须隐藏它,UITabBar因为我希望视图具有尽可能多的空间。
我通过self.hidesBottomBarWhenPushed = YES在 push 内部使用来做到这一点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 的控制器被弹出时,标签栏确实回来了。

UITabBar一旦控制器被隐藏,是否有任何适当的方法可以显示何时按下控制器?

提前致谢

4

3 回答 3

13

hidesBottomBarWhenPushed 未被弃用。我发现使用以下方法实现 UITabBar 的隐藏和显示非常简单:

self.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
self.hidesBottomBarWhenPushed = NO;

因此,在您推送 detailViewConroller 之后,您应该将 hide 属性重置回 NO。这样,当详细视图弹出时,它将再次显示。不需要对 viewWillApear/disapear 等进行任何额外的更改。享受吧。

于 2012-07-15T13:08:56.907 回答
7

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

正如您从文档中阅读的那样,默认行为很明确:一旦视图控制器的hides...属性为 YES,标签栏就会隐藏,直到视图控制器弹出。您想要的直接与此相矛盾,出于各种原因,我首先建议不要采用这种方法。

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


  • hides...属性设置回 NO

您不能修改默认行为。要显示标签栏,堆栈中的所有hides...视图控制器都必须将其属性设置为 NO。因此,从隐藏标签栏的视图中,如果您想在推送新视图时再次显示该栏,则必须再次将先前视图控制器的hides...属性设置回NO

就在你推送一个新的视图控制器之前,将属性设置回 NO。

// ... prepare viewControllerToPush

self.hidesBottomBarWhenPushed = NO;
[self.navigationController pushViewController:viewControllerToPush animated:YES];
[viewControllerToPush release];

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


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

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

为了将标签栏显示回来,Cocoa 修改了它的 layer 的position属性。因此,我们的新方法应该为 key 返回一个动画position,而对于所有其他的 key,它应该使用默认实现。请注意,positionApple 没有记录使用标签栏,因此在以下版本中可能会发生更改,恕不另行通知。无论如何,我们正在实施与 Apple 的规范直接相矛盾的东西,所以不能抱怨太多。

但是,您不能只使用子类化来覆盖该方法。因为即使你有一个自定义的 UITabBar 子类,你也不能修改 UITabBarController 类来使用它来代替默认的 UITabBar。

所以,它变得有点复杂。为了将您自己的逻辑植入到 UITabBar 类中,您必须“交换” message 的实现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

并在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));

您希望在viewDidAppear而不是中执行此操作viewDidLoad,否则标签栏将在应用程序第一次显示时从右侧滑入。

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


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

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

那我的回答到底是为了什么?好吧,我猜是关于 iOS 开发的一些有趣主题的示例(以及证明我今天非常没有生产力的证据:P)。

于 2011-02-22T04:48:38.847 回答
6

这是我在 iOS 5 中使用 Storyboard 时的处理方法:

在执行 push segue 之前将hidesBottomBarWhenPushed属性设置为:NO

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

   [super prepareForSegue:segue sender:sender];
}

segue 标识符显然由你来命名。

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

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

   [super viewWillDisappear:animated];
}

使用所有正确的动画效果就像一个魅力(在 iOS 5.1 上测试)UITabBar

于 2012-07-27T10:32:05.520 回答