[Разработка под iOS, Xcode, Swift] Navigation bar и анимация перехода
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Поведение UINavigationBar при переходе по стеку может показаться непредсказуемым и часто забагованным. Но, на самом деле, так и есть! Эта статья призвана освежить знания о принципах работы и показать возможности кастомизации поведения.Немного общей теорииЕсли вы хорошо осведомлены, смело пролистывайте непосредственно к анимации.
- UINavigationBar – это view. Как правило, его положением управляет UINavigationController, но, так же как и другие view, его можно использовать самостоятельно.
- UINavigationItem – это класс, описывающий состояние (похожее на viewModel) для конфигурации UINavigationBar. Просто класс со свойствами, которые будут переданы в UINavigationBar.
- UINavigationBar содержит массив [UINavigationItem]. С помощью методов pushItem, popItem и setItems можно анимировать переход одного состояния UINavigationBar в другое.
- Каждый UIViewController содержит UINavigationItem. UINavigationController сам управляет добавлением этого свойства в стек item-ов UINavigationBar-а.
Более подробно можно почитать вот здесь:
- https://developer.apple.com/documentation/uikit/uinavigationbar
- https://developer.apple.com/documentation/uikit/uinavigationitem
Также приведу ссылку на полезную схему полного жизненного цикла с UINavigationBar-ом. Это поможет лучше понимать его поведение:
Проблема с изменением высотыUINavigationBar может иметь разную высоту. Это зависит от следующих параметров:
- Наличие или отсутствие prompt (текст над заголовком)
- largeTitleDisplayMode управляет показом большого или стандартного заголовка
Так как UINavigationBar – это одна view, а контроллеров – пара, при переходе анимировано меняется в том числе и высота, что часто урезает контент.Для наглядности покрасим навбар: розовый – это navigationBar.backgroundColor, а зелёный – navigationBar.barTintColor.
Одно из решений – использовать прозрачный backgroundColor. Кстати, backgroundColor – это цвет именно view и он не учитывает смещение на статус-бар.
При переходе между контроллерами с имеющимся prompt-ом такой трюк уже не сработает.
К сожалению, контроля над transition анимацией в самом UINavigationBar мы не имеем. А при использовании UIViewControllerAnimatedTransitioning потеряем анимацию в UINavigationBar. План у нас следующий: добавить адаптацию контента, используя системную анимацию перехода. Создадим несколько контроллеров и используем safeArea для лейаута контента. В последующем смена additionalSafeAreaInsets у UIViewController-а позволит его анимировать:
contentView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
Опишем наследника UINavigationController и добавим реализацию протокола UINavigationControllerDelegate. Это позволит отлавливать событие показа контроллеров, и именно тут будет модифицироваться анимация.
class NavigationController: UINavigationController, UINavigationControllerDelegate { }
Не забудем присвоить делегат самому UINavigationController-у.
navigationController.delegate = navigationController
Далее самое интересное. Ловим UIViewController в методе navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) перед появлением и добавим в transitionCoordinator анимацию для safeArea.
guard let fromViewController = viewController.transitionCoordinator?.viewController(forKey: .from)
else { return }
// Определяем тип анимации. Если контроллера нет в стеке, значит, это pop
let isPopped = !navigationController.viewControllers.contains(fromViewController)
// Добавляем анимацию, которая будет выполнятся одновременно с системной
viewController.transitionCoordinator?.animate { context in
guard let from = context.viewController(forKey: .from),
let to = context.viewController(forKey: .to)
else { return }
// Установка начального состояния
// Перед анимацией задать параметры не выйдет, потому что safeArea изменится
// и расчёты могут быть неверными
UIView.setAnimationsEnabled(false)
let diff = to.view.safeAreaInsets.top - from.view.safeAreaInsets.top
// Выравниваем контент первого контроллера относительно второго
to.additionalSafeAreaInsets.top = -diff
to.view.layoutIfNeeded()
UIView.setAnimationsEnabled(true)
// Анимируем safeArea
to.additionalSafeAreaInsets.top = 0
to.view.layoutIfNeeded()
guard isPopped else { return }
// Изменение фрейма только для pop-анимации
// так как в этом случае additionalSafeAreaInsets не анимируется
from.view.frame.origin.y = diff
from.view.frame.size.height += max(0, -diff)
} completion: { context in
guard let from = context.viewController(forKey: .from),
let to = context.viewController(forKey: .to)
else { return }
from.additionalSafeAreaInsets.top = 0
to.additionalSafeAreaInsets.top = 0
}
Посмотрим, что вышло:
ЗаключениеБезусловно показанный пример – это не универсальный код. Скорее всего, вы ещё сотню раз столкнётесь с проблемами в UINavigationBar. Суть в том, чтобы показать, как понимание основ и принципов может облегчить разработку. Если у вас есть свои интересные решения, буду рад обсудить их в комментариях :)ИсточникиТвиттер:Rtishchev Evgeniihttps://twitter.com/katleta3000/status/1259400743771156480https://stackoverflow.com/questions/39515313/animate-navigation-bar-bartintcolor-change-in-ios10-not-workingЛучшие практики для navigation bar: https://www.programmersought.com/article/1594185256/
===========
Источник:
habr.com
===========
Похожие новости:
- [Игры и игровые приставки, Разработка под iOS] Редиттор перенес клиент Stadia на iOS
- [Flutter, Конференции, Разработка мобильных приложений, Разработка под Android, Разработка под iOS] Нативная разработка vs кроссплатформенная – обсуждаем 30 сентября с владельцами приложений
- [Swift, Софт, IT-компании] Apple открыла исходные тексты Swift System и выложила Swift 5.3
- [Разработка под iOS, Swift] Устройство UI в iOS
- [IT-компании, Разработка под iOS, Смартфоны] Facebook просит Apple разрешить пользователям менять мессенджер по умолчанию в iOS 14
- Apple выпустил язык программирования Swift 5.3 и открыл код библиотеки Swift System
- [Разработка под iOS, Разработка игр, Разработка под Android, Unity, Дизайн игр] Alt: City Online. Как я в одиночку создавал «Gta Online» для мобильных устройств. Часть 1
- [Программирование, Git] Переписывание истории репозитория кода, или почему иногда можно git push -f
- [Системное администрирование, Серверное администрирование, Хранилища данных, DevOps] Пять вопросов о Ceph с пояснениями (перевод)
- [Разработка мобильных приложений, Разработка под Android, Разработка под iOS] Как мы автоматизировали разработку WL-приложений
Теги для поиска: #_razrabotka_pod_ios (Разработка под iOS), #_xcode, #_swift, #_uinavigationcontroller, #_uinavigationcontrollerdelegate, #_uinavigationitem, #_uinavigationbar, #_blog_kompanii_funcorp (
Блог компании FunCorp
), #_razrabotka_pod_ios (
Разработка под iOS
), #_xcode, #_swift
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 20:09
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Поведение UINavigationBar при переходе по стеку может показаться непредсказуемым и часто забагованным. Но, на самом деле, так и есть! Эта статья призвана освежить знания о принципах работы и показать возможности кастомизации поведения.Немного общей теорииЕсли вы хорошо осведомлены, смело пролистывайте непосредственно к анимации.
Проблема с изменением высотыUINavigationBar может иметь разную высоту. Это зависит от следующих параметров:
Одно из решений – использовать прозрачный backgroundColor. Кстати, backgroundColor – это цвет именно view и он не учитывает смещение на статус-бар. При переходе между контроллерами с имеющимся prompt-ом такой трюк уже не сработает. К сожалению, контроля над transition анимацией в самом UINavigationBar мы не имеем. А при использовании UIViewControllerAnimatedTransitioning потеряем анимацию в UINavigationBar. План у нас следующий: добавить адаптацию контента, используя системную анимацию перехода. Создадим несколько контроллеров и используем safeArea для лейаута контента. В последующем смена additionalSafeAreaInsets у UIViewController-а позволит его анимировать: contentView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
class NavigationController: UINavigationController, UINavigationControllerDelegate { }
navigationController.delegate = navigationController
guard let fromViewController = viewController.transitionCoordinator?.viewController(forKey: .from)
else { return } // Определяем тип анимации. Если контроллера нет в стеке, значит, это pop let isPopped = !navigationController.viewControllers.contains(fromViewController) // Добавляем анимацию, которая будет выполнятся одновременно с системной viewController.transitionCoordinator?.animate { context in guard let from = context.viewController(forKey: .from), let to = context.viewController(forKey: .to) else { return } // Установка начального состояния // Перед анимацией задать параметры не выйдет, потому что safeArea изменится // и расчёты могут быть неверными UIView.setAnimationsEnabled(false) let diff = to.view.safeAreaInsets.top - from.view.safeAreaInsets.top // Выравниваем контент первого контроллера относительно второго to.additionalSafeAreaInsets.top = -diff to.view.layoutIfNeeded() UIView.setAnimationsEnabled(true) // Анимируем safeArea to.additionalSafeAreaInsets.top = 0 to.view.layoutIfNeeded() guard isPopped else { return } // Изменение фрейма только для pop-анимации // так как в этом случае additionalSafeAreaInsets не анимируется from.view.frame.origin.y = diff from.view.frame.size.height += max(0, -diff) } completion: { context in guard let from = context.viewController(forKey: .from), let to = context.viewController(forKey: .to) else { return } from.additionalSafeAreaInsets.top = 0 to.additionalSafeAreaInsets.top = 0 } ЗаключениеБезусловно показанный пример – это не универсальный код. Скорее всего, вы ещё сотню раз столкнётесь с проблемами в UINavigationBar. Суть в том, чтобы показать, как понимание основ и принципов может облегчить разработку. Если у вас есть свои интересные решения, буду рад обсудить их в комментариях :)ИсточникиТвиттер:Rtishchev Evgeniihttps://twitter.com/katleta3000/status/1259400743771156480https://stackoverflow.com/questions/39515313/animate-navigation-bar-bartintcolor-change-in-ios10-not-workingЛучшие практики для navigation bar: https://www.programmersought.com/article/1594185256/ =========== Источник: habr.com =========== Похожие новости:
Блог компании FunCorp ), #_razrabotka_pod_ios ( Разработка под iOS ), #_xcode, #_swift |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 20:09
Часовой пояс: UTC + 5