setNavigationBarHidden анимация не работает должным образом на iPhone X
У меня есть код, который входит в полноэкранный режим, скрывая панель навигации UINavigationController. Я хочу плавный анимированный эффект масштабирования при входе в полноэкранный режим. Я использую setNavigationBarHidden (_: animated:). До сих пор все это работало нормально, даже на iOS 11, но на iPhone X анимация работает не очень хорошо. При скрытии анимация отсутствует, а навигационная панель просто исчезает. При отображении он анимируется, но навигационная панель отображается медленнее, чем уменьшается область содержимого контроллера навигации, поэтому во время анимации через область навигационной панели отображается уродливый черный фон.
Я могу воссоздать это в простом тестовом приложении. У меня есть UIViewController, встроенный в UINavigationController.
Раскадровка
- Панель навигации UINavigationController: Стиль == Черный; Прозрачный OFF
- UIViewController: Расширить края: все опции выключены.
Я перепробовал все комбинации "Настроить вставки вида прокрутки" и "Продлить края", которые я могу придумать, но они не имели значения.
Код
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()
}
2 ответа
В вашем случае вы используете оба barTintColor
& navigationBarStyle
с Show
Hide
анимация.barTintColor переопределяет значение, подразумеваемое атрибутом Style. Вы должны выбрать либо barTintColor
или же navigationBarStyle
В приведенном ниже коде я только что использовал 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
со значением bool. & использовать setNeedsStatusBarAppearanceUpdate
override var prefersStatusBarHidden: Bool {
return fullScreen
}
https://developer.apple.com/documentation/uikit/uinavigationbar
Это явно ошибка UIKit. Я подал FB8980917:
При скрытии панели навигации одновременно со строкой состояния с помощью слайд-анимации панель навигации скрывается без анимации. В противоположном направлении строка состояния отображается с анимацией затухания вместо указанной анимации слайда.
Чтобы воспроизвести, запустите прилагаемый образец проекта. Используйте медленную анимацию симулятора или запишите экран устройства и пролистайте кадры.
Я также прикрепил "Screen video.mp4" для справки.
Примечание 1. В качестве обходного пути мы могли бы прибегнуть к устаревшему API UIApplication.setStatusBarHidden(_:with:) (см. «Снимок экрана legacy.mp4»). Это в основном работает, за исключением того, что продолжительность анимации строки состояния больше, чем продолжительность анимации панели навигации. Однако для этого требуется установить UIViewControllerBasedStatusBarAppearance=NO в Info.plist, поэтому это подход «все или ничего», который отказывается от всего приложения современного API.
Примечание 2. Возврат .fade для PreferredStatusBarUpdateAnimation также не работает. Во-первых, это некрасиво, потому что панель навигации все еще выдвигается (и ее нельзя настроить так, чтобы она исчезала), во-вторых, сохраняется проблема отсутствия анимации скрытия панели навигации.
Примечание 3. Использование свойства hidesBarsOnTap UINavigationController также не работает. Проблема остается. В примере приложения также включен 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, работает, я не могу его рекомендовать, поскольку API устарел, начиная с iOS 9.0. Так что на самом деле это должны исправить люди @Apple. Тот факт, что такие приложения, как Photos, реализуют аналогичное поведение без этой ошибки, показывает, что есть способ сделать это, хотя и с помощью частного API или уродливых хаков.