From 4bd9f7f431401a7d48491bd951b0575aa0817b9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 9 Mar 2022 12:57:10 +0100 Subject: [PATCH] MOBILE-3814 collapsible: Use ionScrollEnd to finish animations --- src/core/directives/collapsible-footer.ts | 51 +++++++++--------- src/core/directives/collapsible-header.ts | 66 +++++++++++------------ 2 files changed, 60 insertions(+), 57 deletions(-) diff --git a/src/core/directives/collapsible-footer.ts b/src/core/directives/collapsible-footer.ts index e9fcb9d6b..47fe99439 100644 --- a/src/core/directives/collapsible-footer.ts +++ b/src/core/directives/collapsible-footer.ts @@ -42,9 +42,10 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { protected initialPaddingBottom = '0px'; protected previousTop = 0; protected previousHeight = 0; - protected endAnimationTimeout?: number; protected content?: HTMLIonContentElement | null; protected loadingChangedListener?: CoreEventObserver; + protected contentScrollListener?: EventListener; + protected endContentScrollListener?: EventListener; constructor(el: ElementRef, protected ionContent: IonContent) { this.element = el.nativeElement; @@ -105,7 +106,7 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { const scroll = await this.content.getScrollElement(); this.content.scrollEvents = true; - this.content.addEventListener('ionScroll', (e: CustomEvent): void => { + this.content.addEventListener('ionScroll', this.contentScrollListener = (e: CustomEvent): void => { if (!this.content) { return; } @@ -113,6 +114,23 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { this.onScroll(e.detail, scroll); }); + this.content.addEventListener('ionScrollEnd', this.endContentScrollListener = (): void => { + if (!this.content) { + return; + } + + const height = this.previousHeight; + const collapsed = height <= this.finalHeight; + const expanded = height >= this.initialHeight; + + if (!collapsed && !expanded) { + // Finish opening or closing the bar. + const newHeight = (height - this.finalHeight) < (this.initialHeight - this.finalHeight) / 2 + ? this.finalHeight + : this.initialHeight; + + this.setBarHeight(newHeight); } + }); } /** @@ -154,34 +172,12 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { * @param height The new bar height. */ protected setBarHeight(height: number): void { - if (this.endAnimationTimeout) { - clearTimeout(this.endAnimationTimeout); - } - const collapsed = height <= this.finalHeight; const expanded = height >= this.initialHeight; this.element.classList.toggle('footer-collapsed', collapsed); this.element.classList.toggle('footer-expanded', expanded); this.content?.style.setProperty('--core-collapsible-footer-height', height + 'px'); this.previousHeight = height; - - if (!collapsed && !expanded) { - // Finish opening or closing the bar. - this.endAnimationTimeout = window.setTimeout(() => this.endAnimation(height), 500); - } - } - - /** - * End of animation when not scrolling. - * - * @param height Last height used. - */ - protected endAnimation(height: number): void { - const newHeight = (height - this.finalHeight) < (this.initialHeight - this.finalHeight) / 2 - ? this.finalHeight - : this.initialHeight; - - this.setBarHeight(newHeight); } /** @@ -213,6 +209,13 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { */ async ngOnDestroy(): Promise { this.content?.style.setProperty('--padding-bottom', this.initialPaddingBottom); + + if (this.content && this.contentScrollListener) { + this.content.removeEventListener('ionScroll', this.contentScrollListener); + } + if (this.content && this.endContentScrollListener) { + this.content.removeEventListener('ionScrollEnd', this.endContentScrollListener); + } } } diff --git a/src/core/directives/collapsible-header.ts b/src/core/directives/collapsible-header.ts index 7a0d36d89..01f7b0470 100644 --- a/src/core/directives/collapsible-header.ts +++ b/src/core/directives/collapsible-header.ts @@ -62,11 +62,11 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest protected expandedFontStyles?: Partial; protected content?: HTMLIonContentElement; protected contentScrollListener?: EventListener; + protected endContentScrollListener?: EventListener; protected floatingTitle?: HTMLElement; protected scrollingHeight?: number; protected subscriptions: Subscription[] = []; protected enabled = true; - protected endAnimationTimeout?: number; protected isWithinContent = false; constructor(protected el: ElementRef) {} @@ -108,6 +108,9 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest if (this.content && this.contentScrollListener) { this.content.removeEventListener('ionScroll', this.contentScrollListener); } + if (this.content && this.endContentScrollListener) { + this.content.removeEventListener('ionScrollEnd', this.endContentScrollListener); + } } /** @@ -281,11 +284,17 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest * @param content Content element. */ protected updateContent(content?: HTMLIonContentElement | null): void { - if (this.content && this.contentScrollListener) { - this.content.removeEventListener('ionScroll', this.contentScrollListener); + if (this.content) { + if (this.contentScrollListener) { + this.content.removeEventListener('ionScroll', this.contentScrollListener); + delete this.contentScrollListener; + } + if (this.endContentScrollListener) { + this.content.removeEventListener('ionScrollEnd', this.endContentScrollListener); + delete this.endContentScrollListener; + } delete this.content; - delete this.contentScrollListener; } content && this.trackContentScroll(content); @@ -355,15 +364,12 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest .entries(expandedFontStyles) .forEach(([property, value]) => floatingTitle.style.setProperty(property, value as string)); + this.content.scrollEvents = true; this.content.addEventListener('ionScroll', this.contentScrollListener = ({ target }: CustomEvent): void => { if (target !== this.content || !this.enabled) { return; } - if (this.endAnimationTimeout) { - clearTimeout(this.endAnimationTimeout); - } - const scrollableHeight = contentScroll.scrollHeight - contentScroll.clientHeight; let frozen = false; @@ -384,37 +390,31 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest Object .entries(progress > .5 ? collapsedFontStyles : expandedFontStyles) .forEach(([property, value]) => floatingTitle.style.setProperty(property, value as string)); - - if (progress > 0 && progress < 1) { - // Finish opening or closing the bar. - this.endAnimationTimeout = window.setTimeout(() => this.endAnimation(progress, contentScroll.scrollTop), 500); - } }); - } - /** - * End of animation when stop scrolling. - * - * @param progress Progress. - * @param scrollTop Current ScrollTop position. - */ - protected endAnimation(progress: number, scrollTop: number): void { - if(!this.page) { - return; - } + this.content.addEventListener( + 'ionScrollEnd', + this.endContentScrollListener = ({ target }: CustomEvent): void => { + if (target !== this.content || !this.enabled) { + return; + } - const collapse = progress > 0.5; + const progress = parseFloat(page.style.getPropertyValue('--collapsible-header-progress')); + const scrollTop = contentScroll.scrollTop; + const collapse = progress > 0.5; - this.page.style.setProperty('--collapsible-header-progress', collapse ? '1' : '0'); - this.page.classList.toggle('is-collapsed', collapse); + page.style.setProperty('--collapsible-header-progress', collapse ? '1' : '0'); + page.classList.toggle('is-collapsed', collapse); - if (collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop < this.scrollingHeight) { - this.content?.scrollToPoint(null, this.scrollingHeight); - } + if (collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop < this.scrollingHeight) { + this.content?.scrollToPoint(null, this.scrollingHeight); + } - if (!collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop > 0) { - this.content?.scrollToPoint(null, 0); - } + if (!collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop > 0) { + this.content?.scrollToPoint(null, 0); + } + }, + ); } }