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 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<ScrollDetail>): void => {
this.content.addEventListener('ionScroll', this.contentScrollListener = (e: CustomEvent<ScrollDetail>): 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<void> {
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 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<ScrollDetail>): 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<ScrollDetail>): 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);
}
},
);
}
}