O comportamento de um UINavigationBar ao navegar na pilha pode parecer imprevisível e muitas vezes com erros. Mas, na verdade, é! Este artigo tem como objetivo atualizar seus conhecimentos sobre os princípios de trabalho e mostrar as possibilidades de personalização de comportamentos.
Alguma teoria geral
Se você tiver conhecimento, sinta-se à vontade para rolar diretamente para a animação.
UINavigationBar é uma visualização. Normalmente, sua posição é controlada pelo UINavigationController, mas, como outras visualizações, você mesmo pode usá-lo.
UINavigationItem é uma classe que descreve o estado (semelhante ao viewModel) para a configuração UINavigationBar. Apenas uma classe com propriedades que serão passadas para o UINavigationBar.
O UINavigationBar contém uma matriz [UINavigationItem]. Usando os métodos pushItem, popItem e setItems, você pode animar a transição de um estado UINavigationBar para outro.
Cada UIViewController contém um UINavigationItem. O próprio UINavigationController gerencia a adição dessa propriedade à pilha de itens UINavigationBar.
Mais detalhes podem ser encontrados aqui:
https://developer.apple.com/documentation/uikit/uinavigationbar
https://developer.apple.com/documentation/uikit/uinavigationitem
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 = trueUINavigationController 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 Evgenii https://twitter.com/katleta3000/status/1259400743771156480
navigation bar: https://www.programmersought.com/article/1594185256/