在遍历堆栈时,UINavigationBar的行为似乎是不可预测的,并且经常有问题。但是,实际上是!本文旨在刷新有关工作原理的知识,并展示自定义行为的可能性。
一些一般理论
如果您有足够的知识,请随时直接滚动到动画。
UINavigationBar是一个视图。通常,它的位置由UINavigationController控制,但是像其他视图一样,您可以自己使用它。
UINavigationItem是一个类,用于描述UINavigationBar配置的状态(类似于viewModel)。只是具有将要传递给UINavigationBar的属性的类。
UINavigationBar包含一个数组[UINavigationItem]。使用pushItem,popItem和setItems方法,可以为从一个UINavigationBar状态到另一状态的过渡设置动画。
每个UIViewController包含一个UINavigationItem。UINavigationController本身管理将此属性添加到UINavigationBar项目堆栈中。
更多详情可在这找到:
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 = 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 Evgenii https://twitter.com/katleta3000/status/1259400743771156480
navigation bar: https://www.programmersought.com/article/1594185256/