【问题标题】:Avoid iOS status bar jitter when switching between pages of UIPageViewControllerUIPageViewController页面切换时避免iOS状态栏抖动
【发布时间】:2018-12-16 17:42:20
【问题描述】:

我正在构建一个简单的应用程序,它使用具有两个页面的 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() 方法,我重写了 UIPageViewControllerDelegatedidFinishAnimating 方法强>:

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 动画(如果我把它去掉所以没有动画,它在矩形屏幕上仍然会跳动):

override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
        return .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 屏幕上那样让导航栏随着状态栏向下动画,但这是一种更流畅的体验。如果有人对如何将导航栏固定在同一位置有任何想法,我仍然会很感激。

【问题讨论】:

    标签: ios uipageviewcontroller


    【解决方案1】:

    我会考虑在您的设置控制器中使用additionalSafeAreaInsets,以使其始终考虑状态栏的高度。然后,当您显示状态栏时,您可能必须将其关闭(不是 100% 确定)。

    【讨论】:

    • 谢谢!向该属性添加一些动画解决了跳跃问题。虽然我希望避免导航栏与状态栏一起向下滑动,就像在 iPhone XR 上一样,但您的解决方案通过避免我之前看到的突然的内容跳跃来提供更流畅的体验。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-16
    • 2014-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多