MOBILE-3814 collapsible: Use ionScrollEnd to finish animations

main
Pau Ferrer Ocaña 2022-03-09 12:57:10 +01:00
parent 44ba6878a1
commit 4bd9f7f431
2 changed files with 60 additions and 57 deletions

View File

@ -42,9 +42,10 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
protected initialPaddingBottom = '0px'; protected initialPaddingBottom = '0px';
protected previousTop = 0; protected previousTop = 0;
protected previousHeight = 0; protected previousHeight = 0;
protected endAnimationTimeout?: number;
protected content?: HTMLIonContentElement | null; protected content?: HTMLIonContentElement | null;
protected loadingChangedListener?: CoreEventObserver; protected loadingChangedListener?: CoreEventObserver;
protected contentScrollListener?: EventListener;
protected endContentScrollListener?: EventListener;
constructor(el: ElementRef, protected ionContent: IonContent) { constructor(el: ElementRef, protected ionContent: IonContent) {
this.element = el.nativeElement; this.element = el.nativeElement;
@ -105,7 +106,7 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
const scroll = await this.content.getScrollElement(); const scroll = await this.content.getScrollElement();
this.content.scrollEvents = true; this.content.scrollEvents = true;
this.content.addEventListener('ionScroll', (e: CustomEvent<ScrollDetail>): void => { this.content.addEventListener('ionScroll', this.contentScrollListener = (e: CustomEvent<ScrollDetail>): void => {
if (!this.content) { if (!this.content) {
return; return;
} }
@ -113,6 +114,23 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
this.onScroll(e.detail, scroll); 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. * @param height The new bar height.
*/ */
protected setBarHeight(height: number): void { protected setBarHeight(height: number): void {
if (this.endAnimationTimeout) {
clearTimeout(this.endAnimationTimeout);
}
const collapsed = height <= this.finalHeight; const collapsed = height <= this.finalHeight;
const expanded = height >= this.initialHeight; const expanded = height >= this.initialHeight;
this.element.classList.toggle('footer-collapsed', collapsed); this.element.classList.toggle('footer-collapsed', collapsed);
this.element.classList.toggle('footer-expanded', expanded); this.element.classList.toggle('footer-expanded', expanded);
this.content?.style.setProperty('--core-collapsible-footer-height', height + 'px'); this.content?.style.setProperty('--core-collapsible-footer-height', height + 'px');
this.previousHeight = height; 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<void> { async ngOnDestroy(): Promise<void> {
this.content?.style.setProperty('--padding-bottom', this.initialPaddingBottom); 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);
}
} }
} }

View File

@ -62,11 +62,11 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
protected expandedFontStyles?: Partial<CSSStyleDeclaration>; protected expandedFontStyles?: Partial<CSSStyleDeclaration>;
protected content?: HTMLIonContentElement; protected content?: HTMLIonContentElement;
protected contentScrollListener?: EventListener; protected contentScrollListener?: EventListener;
protected endContentScrollListener?: EventListener;
protected floatingTitle?: HTMLElement; protected floatingTitle?: HTMLElement;
protected scrollingHeight?: number; protected scrollingHeight?: number;
protected subscriptions: Subscription[] = []; protected subscriptions: Subscription[] = [];
protected enabled = true; protected enabled = true;
protected endAnimationTimeout?: number;
protected isWithinContent = false; protected isWithinContent = false;
constructor(protected el: ElementRef) {} constructor(protected el: ElementRef) {}
@ -108,6 +108,9 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
if (this.content && this.contentScrollListener) { if (this.content && this.contentScrollListener) {
this.content.removeEventListener('ionScroll', 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. * @param content Content element.
*/ */
protected updateContent(content?: HTMLIonContentElement | null): void { protected updateContent(content?: HTMLIonContentElement | null): void {
if (this.content && this.contentScrollListener) { if (this.content) {
this.content.removeEventListener('ionScroll', this.contentScrollListener); 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.content;
delete this.contentScrollListener;
} }
content && this.trackContentScroll(content); content && this.trackContentScroll(content);
@ -355,15 +364,12 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
.entries(expandedFontStyles) .entries(expandedFontStyles)
.forEach(([property, value]) => floatingTitle.style.setProperty(property, value as string)); .forEach(([property, value]) => floatingTitle.style.setProperty(property, value as string));
this.content.scrollEvents = true;
this.content.addEventListener('ionScroll', this.contentScrollListener = ({ target }: CustomEvent<ScrollDetail>): void => { this.content.addEventListener('ionScroll', this.contentScrollListener = ({ target }: CustomEvent<ScrollDetail>): void => {
if (target !== this.content || !this.enabled) { if (target !== this.content || !this.enabled) {
return; return;
} }
if (this.endAnimationTimeout) {
clearTimeout(this.endAnimationTimeout);
}
const scrollableHeight = contentScroll.scrollHeight - contentScroll.clientHeight; const scrollableHeight = contentScroll.scrollHeight - contentScroll.clientHeight;
let frozen = false; let frozen = false;
@ -384,37 +390,31 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
Object Object
.entries(progress > .5 ? collapsedFontStyles : expandedFontStyles) .entries(progress > .5 ? collapsedFontStyles : expandedFontStyles)
.forEach(([property, value]) => floatingTitle.style.setProperty(property, value as string)); .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);
}
}); });
}
/** this.content.addEventListener(
* End of animation when stop scrolling. 'ionScrollEnd',
* this.endContentScrollListener = ({ target }: CustomEvent<ScrollDetail>): void => {
* @param progress Progress. if (target !== this.content || !this.enabled) {
* @param scrollTop Current ScrollTop position. return;
*/ }
protected endAnimation(progress: number, scrollTop: number): void {
if(!this.page) {
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'); page.style.setProperty('--collapsible-header-progress', collapse ? '1' : '0');
this.page.classList.toggle('is-collapsed', collapse); page.classList.toggle('is-collapsed', collapse);
if (collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop < this.scrollingHeight) { if (collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop < this.scrollingHeight) {
this.content?.scrollToPoint(null, this.scrollingHeight); this.content?.scrollToPoint(null, this.scrollingHeight);
} }
if (!collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop > 0) { if (!collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop > 0) {
this.content?.scrollToPoint(null, 0); this.content?.scrollToPoint(null, 0);
} }
},
);
} }
} }