setNavigationBarHidden 动画在 iPhone X 上无法正常工作

Posted

技术标签:

【中文标题】setNavigationBarHidden 动画在 iPhone X 上无法正常工作【英文标题】:setNavigationBarHidden animation not working as expected on iPhone X 【发布时间】:2017-11-11 15:41:07 【问题描述】:

我的代码通过隐藏 UINavigationController 的导航栏进入全屏模式。进入全屏时,我想要平滑的动画缩放效果。我使用setNavigationBarHidden(_:animated:)。到目前为止,这一切都运行良好,即使在 ios 11 上也是如此,但在 iPhone X 上动画效果不佳。隐藏时,没有动画,导航栏就消失了。在取消隐藏时,它会进行动画处理,但导航栏的显示速度比导航控制器的内容区域减少的速度要慢,因此在动画期间导航栏区域会显示难看的黑色背景。

我可以在一个简单的测试应用程序中重新创建它。我在 UINavigationController 中嵌入了一个 UIViewController。

故事板

UINavigationController 导航栏:样式 == 黑色;半透明关闭 UIViewController:扩展边缘:关闭所有选项。

我已经尝试了所有我能想到的 Adjust Scroll View Insets 和 Extend Edges 的组合,但它们没有任何区别。

代码

override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)

    setFullScreen(on: fullScreen, animated: animated)


override var prefersStatusBarHidden: Bool

    return fullScreen


override var preferredStatusBarStyle: UIStatusBarStyle

    return .lightContent


@IBAction func onToggleNavBarVisibility(_ sender: Any) 

    if let navBarHidden = self.navigationController?.isNavigationBarHidden 
        // Toggle the state
        fullScreen = !navBarHidden

        setFullScreen(on: fullScreen, animated: true)
    


private func setFullScreen(on : Bool, animated : Bool) 

    self.navigationController?.setNavigationBarHidden(on, animated: animated)
    self.setNeedsStatusBarAppearanceUpdate()

【问题讨论】:

【参考方案1】:

在您的情况下,您同时使用 barTintColornavigationBarStyleShow Hide 动画。 barTintColor 会覆盖 Style 属性所隐含的值 您应该选择barTintColornavigationBarStyle 在下面的代码中,我刚刚使用了barTintColor & navigationBarStyle 默认为Transulent

    var fullScreen = false
      didSet
        self.setNeedsStatusBarAppearanceUpdate()
     
   
    override func viewDidLoad() 
        super.viewDidLoad()
        title = "Navigation Bar"
        navigationController?.navigationBar.barTintColor = .red
    
    override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(true)
        setFullScreen(on: fullScreen, animated: animated)
    
    @IBAction func onToggleNavBarVisibility(_ sender: Any) 
        if let navBarHidden = 
          self.navigationController?.isNavigationBarHidden 
            // Toggle the state
            fullScreen = !navBarHidden
            setFullScreen(on: fullScreen, animated: true)
        
    
    private func setFullScreen(on : Bool, animated : Bool) 
        self.navigationController?.setNavigationBarHidden(on, animated: animated)
        self.setNeedsStatusBarAppearanceUpdate()
    

编辑: 如果要隐藏状态栏- 将prefersStatusBarHidden 与布尔值一起使用。 & 使用setNeedsStatusBarAppearanceUpdate

   override var prefersStatusBarHidden: Bool 
        return fullScreen
    

https://developer.apple.com/documentation/uikit/uinavigationbar

【讨论】:

由于您的图像显示过渡正常工作,这让我更好地理解了问题。您的代码有效的原因是您省略了 prefersStatusBarHidden 覆盖,这似乎是根本原因。真的,我的问题标题是“setNavigationBarHidden 动画不适用于 iPhone X 上的 prefersStatusBarHidden”。注释掉 prefersStatusBarHidden 覆盖使我的代码工作,当然我想隐藏它以获得全屏效果。 (我的原始代码在除 iPhone X 之外的所有 iPhone 模拟器上都能正常工作。) @Ben,请参阅编辑。它可以根据您的需要工作,将prefersStatusBarHidden 替换为UIApplication.shared.isStatusBarHidden = on。不过在 iPhone-X 上保留状态栏还是不错的,状态栏也会显示人们认为有用的信息 很有趣,而且绝对有帮助。虽然不是一个完整的答案,因为(1)状态栏消失没有动画,如果我使用UIApplication.shared.setStatusBarHidden(on, with: .fade),我会收到弃用警告; (2) 现在 Info.plist 中的“基于视图控制器的状态栏外观”应该是 YES; (3) 再现动画还是不太对劲。我感觉出现了一个错误报告...如果您在 iPhone X 上使用照片应用程序,状态栏会在全屏模式下隐藏,所以我想出于临时演示的原因这样做是可以的,我就是这样。【参考方案2】:

这显然是一个 UIKit 错误。我已经提交了 FB8980917:

同时隐藏导航栏和状态栏时 使用幻灯片动画,导航栏隐藏没有动画。 在相反的方向,状态栏出现一个淡入淡出 动画而不是指定的幻灯片动画。

要重现,请运行附加的示例项目。使用模拟器的慢 动画或记录设备的屏幕并逐步浏览帧。

我还附上了一个“屏幕视频.mp4”供您参考。

注意 1:作为一种解决方法,我们可以使用已弃用的 UIApplication.setStatusBarHidden(_:with:) API(参见“屏幕视频 legacy.mp4")。除了状态栏动画外,这主要是有效的 持续时间长于导航栏动画持续时间。 不过需要设置 UIViewControllerBasedStatusBarAppearance=NO 在 Info.plist 所以这是一个 全有或全无的方法,它选择退出现代的整个应用程序 API。

注意 2:为 preferredStatusBarUpdateAnimation 返回 .fade 不会 工作。首先,它很难看,因为导航栏仍然滑动 out (并且不能配置淡出),二是的问题 导航栏缺少隐藏动画仍然存在。

注意 3:使用 UINavigationController 的 hidesBarsOnTap 属性不会 工作。问题依然存在。示例应用程序还具有 hidesBarsOnTap 已启用。

示例代码:

class ViewController: UIViewController 
    var fullScreen = false

    override var prefersStatusBarHidden: Bool 
        return navigationController!.isNavigationBarHidden
    

    override var preferredStatusBarStyle: UIStatusBarStyle 
        return .lightContent
    
    
    override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation 
        return .slide
    

    @IBAction func toggleFullscreen(_ sender: Any) 
        fullScreen = !fullScreen

        navigationController?.setNavigationBarHidden(fullScreen, animated: true)
        setNeedsStatusBarAppearanceUpdate()
    

虽然注释 1 中描述的解决方法有效,但我不能推荐它,因为自 iOS 9.0 起该 API 已被弃用。所以真的,这是由@Apple 来解决这个问题的。诸如照片之类的应用在没有该错误的情况下实现了类似的行为这一事实表明,有一种方法可以做到这一点,尽管使用私有 API 或丑陋的黑客攻击。

【讨论】:

以上是关于setNavigationBarHidden 动画在 iPhone X 上无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

setNavigationBarHidden不起作用

Swift 调用 setNavigationBarHidden 但视图不会移到顶部

setNavigationBarHidden 使整个视图向上/向下滑动

setNavigationBarHidden 在其他类中不起作用(Swift 3.0)

ios UINavgationController setNavigationBarHidden

setNavigationBarHidden 不能以编程方式工作?