【发布时间】: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() 方法,我重写了 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 动画(如果我把它去掉所以没有动画,它在矩形屏幕上仍然会跳动):
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 屏幕上那样让导航栏随着状态栏向下动画,但这是一种更流畅的体验。如果有人对如何将导航栏固定在同一位置有任何想法,我仍然会很感激。
【问题讨论】: