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

在UIPageViewController页面之间切换时避免iOS状态栏抖动,ios,uipageviewcontroller,Ios,Uipageviewcontroller,我正在构建一个简单的应用程序,它使用带有两个页面的UIPageViewController。在一个页面上,我想显示状态栏,但在另一个页面上我不想显示。为了使转换看起来更美观,我在用户完全到达UIPageViewController页面后,将状态栏滑入滑出,具体取决于该页面 这在带有传感器外壳(凹口)的设备(如iPhone XR)上运行良好,但在带有普通矩形屏幕的设备(如iPhone 8)上,它看起来非常油滑 iPhone XR示例-导航栏的高度及其下方的内容保持一致 iPhone 8示例-当状

我正在构建一个简单的应用程序,它使用带有两个页面的UIPageViewController。在一个页面上,我想显示状态栏,但在另一个页面上我不想显示。为了使转换看起来更美观,我在用户完全到达UIPageViewController页面后,将状态栏滑入滑出,具体取决于该页面

这在带有传感器外壳(凹口)的设备(如iPhone XR)上运行良好,但在带有普通矩形屏幕的设备(如iPhone 8)上,它看起来非常油滑

iPhone XR示例-导航栏的高度及其下方的内容保持一致

iPhone 8示例-当状态栏开始设置动画(滑动)时,内容会跳起来,但当导航栏设置动画时,内容会返回到原始位置


最佳解决方案?

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


现有代码

在我的UIPageViewController上,我跟踪currentViewController属性,并相应地更新覆盖的prefersStatusBarHidden变量

private var currentViewController: UIViewController?

override var prefersStatusBarHidden: Bool {
    if let current = currentViewController,
        current == settingsNavigationController {
        return false
    } else {
        return true
    }
}
要设置currentViewController变量并调用必要的setNeedsStatusBarAppearanceUpdate()方法,我覆盖UIPageViewControllerDelegate的didFinishAnimating方法:

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()
        }
    }
}
为了减少震动,我使用了.slide动画(如果我不使用它,因此没有动画,它在矩形屏幕上仍然会跳动):


更新:

多亏了Leon Deriglazov的回答,我通过对
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
    }
}
注意:这不包含检测设备类型所需的附加逻辑

下面是它的样子:


理想情况下,我不想让导航栏与状态栏一起设置动画,就像在iPhone XR屏幕上一样,这是一种更加流畅的体验。如果有人对如何保持导航条保持在同一个位置上有任何想法,我仍然很感激。

< P>我会考虑在您的设置控制器中使用<代码> AudialSeaSeriaEngs<代码>,以使它始终说明状态栏的高度。然后,当您显示状态栏时,您可能必须将其关闭(对此不是100%确定)。

谢谢!向该属性添加一些动画解决了跳跃问题。理想情况下,我希望避免导航栏与状态栏一起向下滑动,就像在iPhone XR上一样,但您的解决方案通过避免我以前看到的内容突然跳转,提供了更加流畅的体验。
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
    }
}