scroll end timing

This commit is contained in:
Tanner Reits
2024-10-11 15:49:15 -04:00
parent 9823e0d2a9
commit 1bb7fe87f7
2 changed files with 12 additions and 78 deletions

View File

@ -71,18 +71,18 @@ export class SegmentView implements ComponentInterface {
// Find the current segment content based on the scroll position // Find the current segment content based on the scroll position
const currentIndex = Math.round(scrollLeft / offsetWidth); const currentIndex = Math.round(scrollLeft / offsetWidth);
// Recursively search for the next enabled content in the scroll direction // // Update active content ID and scroll to the segment content
const segmentContent = this.getNextEnabledContent(currentIndex, scrollDirection); const activeContent = this.getSegmentContents().filter(
(ref) => !ref.classList.contains('segment-content-disabled')
)[currentIndex];
this.activeContentId = activeContent.id;
// Exit if no valid segment content found // Only emit scroll end event if the active content is not disabled and
if (!segmentContent) return; // the user is not touching the segment view
if (activeContent?.disabled === false && !this.isTouching) {
// Update active content ID and scroll to the segment content this.ionSegmentViewScrollEnd.emit({ activeContentId: this.activeContentId });
this.activeContentId = segmentContent.id; this.initialScrollLeft = undefined;
this.setContent(segmentContent.id); }
// Reset the timeout to check for scroll end
this.resetScrollEndTimeout();
} }
/** /**
@ -108,35 +108,6 @@ export class SegmentView implements ComponentInterface {
this.isTouching = false; this.isTouching = false;
} }
/**
* Reset the scroll end detection timer. This is called on every scroll event.
*/
private resetScrollEndTimeout() {
if (this.scrollEndTimeout) {
clearTimeout(this.scrollEndTimeout);
this.scrollEndTimeout = null;
}
this.scrollEndTimeout = setTimeout(() => {
this.checkForScrollEnd();
}, 150);
}
/**
* Check if the scroll has ended and the user is not actively touching.
* If the conditions are met (active content is enabled and no active touch),
* reset the scroll position and emit the scroll end event.
*/
private checkForScrollEnd() {
const activeContent = this.getSegmentContents().find((content) => content.id === this.activeContentId);
// Only emit scroll end event if the active content is not disabled and
// the user is not touching the segment view
if (activeContent?.disabled === false && !this.isTouching) {
this.ionSegmentViewScrollEnd.emit({ activeContentId: this.activeContentId });
this.initialScrollLeft = undefined;
}
}
/** /**
* This method is used to programmatically set the displayed segment content * This method is used to programmatically set the displayed segment content
* in the segment view. Calling this method will update the `value` of the * in the segment view. Calling this method will update the `value` of the

View File

@ -28,8 +28,6 @@ export class Segment implements ComponentInterface {
private valueBeforeGesture?: SegmentValue; private valueBeforeGesture?: SegmentValue;
private segmentViewEl?: HTMLIonSegmentViewElement | null = null; private segmentViewEl?: HTMLIonSegmentViewElement | null = null;
private scrolledIndicator?: HTMLDivElement | null = null;
private isScrolling = false;
@Element() el!: HTMLIonSegmentElement; @Element() el!: HTMLIonSegmentElement;
@ -381,10 +379,6 @@ export class Segment implements ComponentInterface {
@Listen('ionSegmentViewScroll', { target: 'body' }) @Listen('ionSegmentViewScroll', { target: 'body' })
handleSegmentViewScroll(ev: CustomEvent) { handleSegmentViewScroll(ev: CustomEvent) {
if (!this.isScrolling) {
return;
}
const dispatchedFrom = ev.target as HTMLElement; const dispatchedFrom = ev.target as HTMLElement;
const segmentViewEl = this.segmentViewEl as EventTarget; const segmentViewEl = this.segmentViewEl as EventTarget;
const segmentEl = this.el; const segmentEl = this.el;
@ -464,6 +458,7 @@ export class Segment implements ComponentInterface {
indicator.querySelector('div')!.style.backgroundColor = color; indicator.querySelector('div')!.style.backgroundColor = color;
} }
// Scroll the segment container if the indicator is out of view
const indicatorX = indicator.getBoundingClientRect().x; const indicatorX = indicator.getBoundingClientRect().x;
if (scrollDistance < 0 && indicatorX < 0) { if (scrollDistance < 0 && indicatorX < 0) {
this.el.scrollBy({ this.el.scrollBy({
@ -482,17 +477,6 @@ export class Segment implements ComponentInterface {
} }
} }
@Listen('ionSegmentViewScrollStart', { target: 'body' })
onScrollStart(ev: CustomEvent) {
const dispatchedFrom = ev.target as HTMLElement;
const segmentViewEl = this.segmentViewEl as EventTarget;
const segmentEl = this.el;
if (ev.composedPath().includes(segmentViewEl) || dispatchedFrom?.contains(segmentEl)) {
this.isScrolling = true;
}
}
@Listen('ionSegmentViewScrollEnd', { target: 'body' }) @Listen('ionSegmentViewScrollEnd', { target: 'body' })
onScrollEnd(ev: CustomEvent<{ activeContentId: string }>) { onScrollEnd(ev: CustomEvent<{ activeContentId: string }>) {
const dispatchedFrom = ev.target as HTMLElement; const dispatchedFrom = ev.target as HTMLElement;
@ -500,31 +484,10 @@ export class Segment implements ComponentInterface {
const segmentEl = this.el; const segmentEl = this.el;
if (ev.composedPath().includes(segmentViewEl) || dispatchedFrom?.contains(segmentEl)) { if (ev.composedPath().includes(segmentViewEl) || dispatchedFrom?.contains(segmentEl)) {
this.isScrolling = false;
this.value = ev.detail.activeContentId; this.value = ev.detail.activeContentId;
} }
} }
// Wait for the transition to end, then execute the callback
private waitForTransitionEnd(indicator: HTMLElement, callback: () => void) {
const onTransitionEnd = () => {
indicator.removeEventListener('transitionend', onTransitionEnd);
callback();
};
indicator.addEventListener('transitionend', onTransitionEnd);
}
// Update the Segment value after the ionSegmentViewScrollEnd transition has ended
private updateValueAfterTransition(activeContentId: string) {
this.value = activeContentId;
if (this.scrolledIndicator) {
this.scrolledIndicator.style.transition = '';
this.scrolledIndicator.style.transform = '';
}
}
/** /**
* Finds the related segment view and sets its current content * Finds the related segment view and sets its current content
* based on the selected segment button. This method * based on the selected segment button. This method