スタックをナビゲートするときの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/