代码之家  ›  专栏  ›  技术社区  ›  gohnjanotis

在uipageviewcontroller的页面之间切换时避免iOS状态栏抖动

  •  1
  • gohnjanotis  · 技术社区  · 6 年前

    我正在构建一个使用 uipageview控制器 两页纸。在一个页面上,我想显示状态栏,但在另一个页面上,我不想。为了使转换看起来更漂亮,我在用户完全到达 uipageview控制器 ,取决于它是哪个页面。

    这在传感器外壳(凹口)的设备(如iPhoneXR)上很管用,但在具有普通矩形屏幕(如iPhone8)的设备上,它看起来非常华丽。

    iPhone xr示例 艾斯 导航栏的高度和下面的内容保持一致。

    iPhone XR example GIF

    iPhone 8示例 艾斯 当状态栏开始在中设置动画(滑动)时,内容将向上跳,但当导航栏向下设置动画时,内容将返回到其原始位置。

    iPhone 8 example GIF


    最佳解决方案?

    似乎最好的解决方案之一就是以某种方式强制导航栏始终是导航栏的全高+状态栏的高度,因此导航栏和内容保持在同一位置,而状态栏向下显示动画。这将类似于iPhonexr屏幕上的行为。我怎样才能做到这一点?


    现有代码

    在我身上 uipageview控制器 ,我跟踪 当前视图控制器 属性,并更新重写的 首选项状态栏隐藏 相应的变量。

    private var currentViewController: UIViewController?
    
    override var prefersStatusBarHidden: Bool {
        if let current = currentViewController,
            current == settingsNavigationController {
            return false
        } else {
            return true
        }
    }
    

    设置 当前视图控制器 变量并调用 setNeedsstatusBarAppearanceUpdate()。 方法,我重写 未完成动画制作 方法 uipageViewControllerDelegate :

    extension PageViewController: UIPageViewControllerDelegate {
    
        func pageViewController(_ pageViewController: UIPageViewController,
                                didFinishAnimating finished: Bool,
                                previousViewControllers: [UIViewController],
                                transitionCompleted completed: Bool) {
    
            currentViewController = pageViewController.viewControllers?.first
    
            UIView.animate(withDuration: 0.2) { () -> Void in
                self.setNeedsStatusBarAppearanceUpdate()
            }
        }
    }
    

    为了减少震动,我使用 幻灯片 动画(如果我把它放在一边,这样就没有动画了,它在矩形屏幕上仍然会跳动):

    override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
            return .slide
    }
    

    更新:

    多亏了 列昂-德里加佐夫 我的回答是,我已经能够通过将 UINavigationController . 我添加了以下代码来触发一个动画(与状态栏动画的持续时间相同),该动画在状态栏向下滑动时向上移动内容,使内容看起来保持在同一位置:

    class SettingsNavigationController: UINavigationController {
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
    
            UIView.animate(withDuration: 0.2) {
                self.additionalSafeAreaInsets.top = 0
            }
        }
    
        override func viewDidDisappear(_ animated: Bool) {
            super.viewDidDisappear(animated)
    
            additionalSafeAreaInsets.top = 20
        }
    }
    

    注意:这不包含检测设备类型所需的附加逻辑。

    它看起来是这样的:

    fixed jitter

    虽然理想情况下我不想让导航栏和状态栏一起显示动画,就像在iPhonexr屏幕上一样,但这是一种更流畅的体验。如果有人对如何将导航栏固定在同一位置有任何想法,我还是会很感激的。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Leon Deriglazov    6 年前

    我会考虑雇用 additionalSafeAreaInsets 在您的设置控制器中,使其始终占据状态栏的高度。然后,您可能需要在显示状态栏时将其关闭(对此不完全确定)。