【问题标题】:How do I "legally" fade out the navigation bar in an app?我如何“合法地”淡出应用程序中的导航栏?
【发布时间】:2013-07-28 15:08:40
【问题描述】:

似乎删除带有动画的导航栏的唯一方法是向上滑动。我希望它褪色,就像在 Photos.app 中一样。

更改 alpha 是最简单的,但是 Apple's guidelines state:

在 iOS v5.0 之前,与导航一起使用时 控制器,您只能进行少数直接自定义 进入导航栏。具体可以修改 barStyle、tintColor 和 translucent 属性,但绝不能 直接更改 UIView 级别的属性,例如框架、边界、 alpha,或者直接隐藏属性。

该语言有点奇怪,就像它在 iOS 5 之前的声明一样,但它声明你不能直接更改 alpha 值,而且它从来没有声明你现在可以这样做。

我不希望我的应用被拒绝。

如何像淡出状态栏一样淡出导航栏?

【问题讨论】:

  • Hmmmm ...“修改 [...] 半透明属性”但“从不直接更改 [...] alpha ...”怎么可能?如何改变半透明度改变alpha???
  • 同意,我也很困惑。编辑:您可以访问一个“半透明”属性,但它只是“是”或“否”,设置为“是”并不完全透明。
  • 我认为“你绝不能......”作为警告,如果你尝试,某些东西会破裂,而不是作为拒绝的威胁。 App Store 拒绝也可能发生,但更有可能是因为您的应用被破坏而不是因为不听警告而受到惩罚。
  • 你为什么将我的答案标记为正确并将赏金给其他人?

标签: ios objective-c uiview uinavigationcontroller uinavigationbar


【解决方案1】:

您不能合法地为 UINavigationController 的导航栏属性设置动画。
但是,您可以显示带有隐藏导航栏的导航控制器(根据您的喜好,始终或仅在特定视图控制器上隐藏它),并将其替换为 UINavigationBar 的“特殊”实例;-)

我附上了一个示例项目(我使用 Xcode 模板更快地创建它):FakeNavBar

DetailViewControllerviewDidLoad方法:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self configureView];

    self.fakeBar = [[UINavigationBar alloc]initWithFrame:self.navigationController.navigationBar.bounds];


    UIBarButtonItem *back = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(back)];



    UINavigationItem *backItem = [[UINavigationItem alloc]initWithTitle:@"Back"];
    backItem.leftBarButtonItem = back;
    [self.fakeBar pushNavigationItem:backItem animated:YES];

    [self.view addSubview:self.fakeBar];

}

这是最终产品的视频on YouTube

【讨论】:

  • 现在 this 很酷。我回家看看,谢谢。
  • 一个明显的问题是你的假“后退”按钮没有被设计为后退按钮(没有左尖箭头)。如果您使用标准的 UIViewController navigationItem 属性(例如,您将它们设置在 nib/storyboard 中),您还必须跳过一堆障碍。我不喜欢以这种方式重新发明轮子。
  • @TomSwift ,首先,如果反对票是你的,我希望你知道应该对不正确的答案投反对票,而不是因为你不喜欢的答案。现在,谈到答案,后退按钮不是问题:因为解释导航项堆栈的工作原理不是答案的目标,所以我更愿意只关注主要问题。为了防止这个“问题”,添加一堆导航项以将普通箭头作为后退按钮就足够了。此外,(在下一条评论中继续)
  • 如果您强烈了解并理解这种情况下的工作原理,就没有理由“跳过一堆麻烦”。例如,您可以将所有代码放在一个超类中,此外,您还可以复制原始导航控制器的导航项。检查最后一个示例(再次:5 分钟代码,现在您可以在 nib 中设置标题或其他按钮):link(仅在要启用特殊行为的 VC 上使用超类,即使使用更长的时间也可以使用导航堆栈,显然有一些调试)
  • 完全正确。对我来说,这听起来像是一堆箍跳。 ;)
【解决方案2】:

这是一个有趣的解决方案。

它应该非常简单:使用UIView transitionWithView 在导航栏的隐藏和非隐藏状态之间执行交叉淡入淡出,由公共 API setNavigationBarHidden:animated: 设置。实际上,这适用于“淡出”导航栏,但将其淡入会出现问题。问题是导航栏会滑动到位,不管UIView +transitionWithView: 不会为动画属性(例如frame)设置动画,除非您指定UIViewAnimationOptionAllowAnimatedContent

对我来说,这意味着UINavigationController 在内部将UINavigationBar 重新定位在动画块内,无论是否在对setNavigationBarHidden:animated: 的调用中指定了动画。当animate: 设置为NO 时,此动画块的持续时间可能设置为“0”。

解决方案是在交叉淡入淡出过渡之前设置导航栏可见(无动画)。这样可以确保导航栏在正确的位置开始淡入淡出,并且淡入淡出只会显示新的非隐藏状态。

我的示例项目是一个标准的单视图应用程序。故事板上有一个UINavigationController,它是入口点。我将此控制器的UINavigationBar 的条形样式设置为黑色半透明(类似于照片应用程序)。导航控制器的rootViewController 是一个简单的UIViewControllerUIImageView 填充整个边界(也像照片应用程序)。我在视图上添加了UITapGestureRecognizer 以在视图控制器中调用以下代码:

- (IBAction) onShowHideNavbar: (id) sender
{
    BOOL hide = !self.navigationController.navigationBarHidden;

    if ( !hide)
    {
        [self.navigationController setNavigationBarHidden: hide animated: NO];
    }

    [UIView transitionWithView: self.navigationController.view
                      duration: 1
                       options: UIViewAnimationOptionTransitionCrossDissolve
                    animations: ^{

                        [self.navigationController setNavigationBarHidden: hide animated: NO];
                    }
                    completion: nil ];
}

所有这一切,我认为你不会因为直接弄乱UINavigationBar 的隐藏或 alpha 属性而遇到任何麻烦(Apple 拒绝)。文档警告不要触摸这些,因为它们由 UINavigationController 管理,并且更改它们可能会产生看不见的后果。但在我看来,它们是公共 API,因此使用它们不应成为拒绝的理由。

【讨论】:

  • 当您在 UINavigationController 上显示-隐藏导航栏时,内容视图框架会发生变化。因此,调整了主控制器的大小。如果你使用这段代码,你会遇到两个问题:首先,你会看到导航栏后面是黑色的背景,直到动画结束(如果你使用了带有黑色边框的图像,比如photos.app,你可能没有看到它)。第二:动画完成后,主视图会自动调整大小,没有动画,有一个跳转。不太好。淡入也有问题,看这里:[link](youtu.be/jdChWTkPGGw)
  • 是的,你会得到一个不透明的导航栏的跳跃。如果您将导航栏设置为半透明黑色(正如我在答案中所说),它不会跳转,因为内容视图已经在它后面。如果您需要完全不透明条的功能,则需要做更多的工作。
  • 你是对的,我的错。当您使用半透明栏时,视图会延伸到导航栏下方,因此动画中不会出现“跳跃”。使用 opaque bar,技巧应该是您在聊天中建议的 WantFullScreenLayout,但由于某种原因,我无法使其正常工作
【解决方案3】:

您可能无法轻松淡化导航栏,但您可以轻松淡化导航栏的图片。所以你可以做的一件事是创建导航栏的图像,用你的图像替换导航栏,然后用 alpha 为 0 设置图像视图的动画。或者你可以做相反的事情:将图像视图放在顶部导航栏,并淡入应该在导航栏后面的任何图像。

【讨论】:

    【解决方案4】:

    如果您继续阅读,这是您引用之后的下一段:

    在 iOS v5.0 及更高版本中,您可以自定义栏的外观 使用“自定义条形外观”中列出的方法。你可以 使用外观自定义所有导航栏的外观 代理([UINavigationBar 外观]),或者只是单个条。

    单击链接(自定义栏外观)将显示:

    自定义条形外观
    tintColor 属性
    – backgroundImageForBarMetrics:
    – setBackgroundImage:forBarMetrics:
    – titleVerticalPositionAdjustmentForBarMetrics:
    – setTitleVerticalPositionAdjustment:forBarMetrics:
    titleTextAttributes 属性

    因此,在 iOS v5.0 及更高版本中,您可以(合法地)更改该列表。您可能可以使用 tintColor 的 alpha 或背景图像玩一些游戏,以使其看起来像是淡出(然后将其隐藏),但我怀疑它看起来是否正确。不过可能值得一试。

    【讨论】:

      【解决方案5】:

      我知道没有 Apple 认可的方法可以做到这一点。我怀疑你会因为修改 navigationBar 的 alpha 值而被拒绝,但和你一样,我不确定。

      您当然可以实现自己的导航控制器/导航栏,用它可以做任何您想做的事情。当我需要做这样的事情时,这就是我在我的应用程序中所做的。苹果对此完全没有问题。加分项:如果您使用自定义控件,Apple 可以随意更改其控件,而不会破坏您的布局。这是最近在我们应用程序的某些区域中出现的问题,在不同版本的 iOS (7) 中,应用程序看起来非常不同。

      无论如何,这是我的 2 美分...

      【讨论】:

        【解决方案6】:

        解决这个问题的方法(我不确切知道您打算如何为下一个视图设置动画或以何种方式合并淡入淡出)是将当前视图渲染为 uiimage,制作全屏 UIImageView用这个图像(基本上用它的图片替换你现有的 UIView )在图像视图后面交换你的新视图,然后淡出图像视图。

        您还可以仅裁剪图像的 UInavigationBar 部分,并在过渡后将其淡化。这样您就可以将任何图像效果应用到“UINavgationBar”而不会被苹果拒绝。

        【讨论】:

        • 可悲的是,在苹果控制的世界里,像这样的技巧通常是获得某些效果的唯一方法。可能有更好的方法,如果您没有找到其他方法,我只会给您一个想法。
        • UIView 中有一个新的“快照”支持(在 b4 中刚刚更改)可能会有所帮助?
        • 不幸的是,当淡入淡出发生时,我需要在 UIView 中发生一些事情,因此静态图像无论如何都不起作用。不幸的是,verec 暂时只能在 iOS 6 上运行。
        • 他可以简单地使用自定义导航栏而不是导航控制器提供的导航栏,它是如此简单......道格,看看我的答案;-)
        • LombaX 做得很好,这是我所说的更好的方式。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-29
        • 1970-01-01
        • 1970-01-01
        • 2023-01-16
        相关资源
        最近更新 更多