@@ -146,6 +146,7 @@ final class DashboardViewController: UIViewController {
146146
147147 override func viewDidAppear( _ animated: Bool ) {
148148 super. viewDidAppear ( animated)
149+ updateHeaderVisibility ( animated: false )
149150 observeNavigationBarHeightForHeaderVisibility ( )
150151 }
151152
@@ -162,48 +163,78 @@ final class DashboardViewController: UIViewController {
162163 override var shouldShowOfflineBanner : Bool {
163164 return true
164165 }
166+ }
165167
166- func showHeader( ) {
168+ // MARK: - Header animation
169+ private extension DashboardViewController {
170+ func showHeaderWithoutAnimation( ) {
167171 contentTopToHeaderConstraint? . isActive = true
168172 headerStackView. alpha = 1
169173 view. layoutIfNeeded ( )
170174 }
171175
172- func hideHeader ( ) {
176+ func hideHeaderWithoutAnimation ( ) {
173177 contentTopToHeaderConstraint? . isActive = false
174178 headerStackView. alpha = 0
175179 view. layoutIfNeeded ( )
176180 }
177181
178- func showHeaderWithAnimation( ) {
179- if headerAnimator? . isRunning == true {
180- headerAnimator? . stopAnimation ( true )
182+ func updateHeaderVisibility( animated: Bool ) {
183+ if navigationBarIsCollapsed ( ) {
184+ hideHeader ( animated: animated)
185+ } else {
186+ showHeader ( animated: animated)
181187 }
182- headerAnimator = UIViewPropertyAnimator . runningPropertyAnimator (
183- withDuration: Constants . animationDurationSeconds,
184- delay: 0 ,
185- animations: { [ weak self] in
186- self ? . showHeader ( )
187- } ,
188- completion: { [ weak self] position in
189- self ? . headerAnimator = nil
190- } )
191188 }
192189
193- func hideHeaderWithAnimation( ) {
190+ func showHeader( animated: Bool ) {
191+ if animated {
192+ animateHeaderVisibility {
193+ self . showHeaderWithoutAnimation ( )
194+ }
195+ } else {
196+ showHeaderWithoutAnimation ( )
197+ }
198+ }
199+
200+ func hideHeader( animated: Bool ) {
201+ if animated {
202+ animateHeaderVisibility {
203+ self . hideHeaderWithoutAnimation ( )
204+ }
205+ } else {
206+ hideHeaderWithoutAnimation ( )
207+ }
208+ }
209+
210+ func animateHeaderVisibility( animations: @escaping ( ) -> Void ) {
194211 if headerAnimator? . isRunning == true {
195212 headerAnimator? . stopAnimation ( true )
196213 }
197214 headerAnimator = UIViewPropertyAnimator . runningPropertyAnimator (
198215 withDuration: Constants . animationDurationSeconds,
199216 delay: 0 ,
200- animations: { [ weak self] in
201- self ? . hideHeader ( )
202- } ,
217+ animations: animations,
203218 completion: { [ weak self] position in
204219 self ? . headerAnimator = nil
205220 } )
206221 }
222+
223+ func navigationBarIsCollapsed( ) -> Bool {
224+ guard let frame = navigationController? . navigationBar. frame else {
225+ return false
226+ }
227+
228+ return frame. height <= collapsedNavigationBarHeight
229+ }
230+
231+ var collapsedNavigationBarHeight : CGFloat {
232+ if self . traitCollection. userInterfaceIdiom == . pad {
233+ return Constants . iPadCollapsedNavigationBarHeight
234+ } else {
235+ return Constants . iPhoneCollapsedNavigationBarHeight
236+ }
237+ }
207238}
208239
209240// MARK: - Configuration
@@ -644,34 +675,23 @@ private extension DashboardViewController {
644675 }
645676
646677 func observeNavigationBarHeightForHeaderVisibility( ) {
647- navbarObserverSubscription = navigationController? . navigationBar. publisher ( for: \. frame, options: [ . initial, . new] )
648- . map ( { [ collapsedNavigationBarHeight] rect in
649- rect. height <= collapsedNavigationBarHeight
650- } ) // true if navigation bar is collapsed
678+ navbarObserverSubscription = navigationController? . navigationBar. publisher ( for: \. frame, options: [ . new] )
679+ . map ( { [ weak self] rect in
680+ // This seems useless given that we're discarding the value later
681+ // and recalculating within updateHeaderVisibility, but this is an easy
682+ // way to avoid constant updates with the `removeDuplicates` that follows
683+ self ? . navigationBarIsCollapsed ( ) ?? false
684+ } )
651685 . removeDuplicates ( )
652- . sink ( receiveValue: { [ weak self] navigationBarIsShort in
653- guard let self else { return }
654-
655- if navigationBarIsShort {
656- self . hideHeaderWithAnimation ( )
657- } else {
658- self . showHeaderWithAnimation ( )
659- }
686+ . sink ( receiveValue: { [ weak self] _ in
687+ self ? . updateHeaderVisibility ( animated: true )
660688 } )
661689 }
662690
663691 func stopObservingNavigationBarHeightForHeaderVisibility( ) {
664692 navbarObserverSubscription? . cancel ( )
665693 navbarObserverSubscription = nil
666694 }
667-
668- var collapsedNavigationBarHeight : CGFloat {
669- if self . traitCollection. userInterfaceIdiom == . pad {
670- return Constants . iPadCollapsedNavigationBarHeight
671- } else {
672- return Constants . iPhoneCollapsedNavigationBarHeight
673- }
674- }
675695}
676696
677697// MARK: Constants
0 commit comments