mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 03:00:58 +08:00
fix(segment-view): allow moving the indicator left on scroll without touch
This commit is contained in:
@ -1613,6 +1613,8 @@ ion-segment-content,prop,disabled,boolean,false,false,false
|
|||||||
ion-segment-view,shadow
|
ion-segment-view,shadow
|
||||||
ion-segment-view,prop,disabled,boolean,false,false,false
|
ion-segment-view,prop,disabled,boolean,false,false,false
|
||||||
ion-segment-view,method,setContent,setContent(id: string, smoothScroll?: boolean) => Promise<void>
|
ion-segment-view,method,setContent,setContent(id: string, smoothScroll?: boolean) => Promise<void>
|
||||||
|
ion-segment-view,event,ionSegmentViewScroll,{ scrollDirection: string; scrollDistance: number; },true
|
||||||
|
ion-segment-view,event,ionSegmentViewScrollEnd,void,true
|
||||||
|
|
||||||
ion-select,shadow
|
ion-select,shadow
|
||||||
ion-select,prop,cancelText,string,'Cancel',false,false
|
ion-select,prop,cancelText,string,'Cancel',false,false
|
||||||
|
8
core/src/components.d.ts
vendored
8
core/src/components.d.ts
vendored
@ -4443,6 +4443,7 @@ declare global {
|
|||||||
};
|
};
|
||||||
interface HTMLIonSegmentViewElementEventMap {
|
interface HTMLIonSegmentViewElementEventMap {
|
||||||
"ionSegmentViewScroll": { scrollDirection: string; scrollDistance: number };
|
"ionSegmentViewScroll": { scrollDirection: string; scrollDistance: number };
|
||||||
|
"ionSegmentViewScrollEnd": void;
|
||||||
}
|
}
|
||||||
interface HTMLIonSegmentViewElement extends Components.IonSegmentView, HTMLStencilElement {
|
interface HTMLIonSegmentViewElement extends Components.IonSegmentView, HTMLStencilElement {
|
||||||
addEventListener<K extends keyof HTMLIonSegmentViewElementEventMap>(type: K, listener: (this: HTMLIonSegmentViewElement, ev: IonSegmentViewCustomEvent<HTMLIonSegmentViewElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
|
addEventListener<K extends keyof HTMLIonSegmentViewElementEventMap>(type: K, listener: (this: HTMLIonSegmentViewElement, ev: IonSegmentViewCustomEvent<HTMLIonSegmentViewElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
|
||||||
@ -7534,7 +7535,14 @@ declare namespace LocalJSX {
|
|||||||
* If `true`, the segment view cannot be interacted with.
|
* If `true`, the segment view cannot be interacted with.
|
||||||
*/
|
*/
|
||||||
"disabled"?: boolean;
|
"disabled"?: boolean;
|
||||||
|
/**
|
||||||
|
* Emitted when the segment view is scrolled.
|
||||||
|
*/
|
||||||
"onIonSegmentViewScroll"?: (event: IonSegmentViewCustomEvent<{ scrollDirection: string; scrollDistance: number }>) => void;
|
"onIonSegmentViewScroll"?: (event: IonSegmentViewCustomEvent<{ scrollDirection: string; scrollDistance: number }>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the segment view scroll has ended.
|
||||||
|
*/
|
||||||
|
"onIonSegmentViewScrollEnd"?: (event: IonSegmentViewCustomEvent<void>) => void;
|
||||||
}
|
}
|
||||||
interface IonSelect {
|
interface IonSelect {
|
||||||
/**
|
/**
|
||||||
|
@ -10,8 +10,10 @@ import { Component, Element, Event, Host, Listen, Method, Prop, h } from '@stenc
|
|||||||
shadow: true,
|
shadow: true,
|
||||||
})
|
})
|
||||||
export class SegmentView implements ComponentInterface {
|
export class SegmentView implements ComponentInterface {
|
||||||
private initialScrollLeft = 0;
|
private initialScrollLeft?: number;
|
||||||
private previousScrollLeft = 0;
|
private previousScrollLeft = 0;
|
||||||
|
private scrollEndTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
private isTouching = false;
|
||||||
|
|
||||||
@Element() el!: HTMLElement;
|
@Element() el!: HTMLElement;
|
||||||
|
|
||||||
@ -20,21 +22,31 @@ export class SegmentView implements ComponentInterface {
|
|||||||
*/
|
*/
|
||||||
@Prop() disabled = false;
|
@Prop() disabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted when the segment view is scrolled.
|
||||||
|
*/
|
||||||
@Event() ionSegmentViewScroll!: EventEmitter<{ scrollDirection: string; scrollDistance: number }>;
|
@Event() ionSegmentViewScroll!: EventEmitter<{ scrollDirection: string; scrollDistance: number }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted when the segment view scroll has ended.
|
||||||
|
*/
|
||||||
|
@Event() ionSegmentViewScrollEnd!: EventEmitter<void>;
|
||||||
|
|
||||||
@Listen('scroll')
|
@Listen('scroll')
|
||||||
handleScroll(ev: Event) {
|
handleScroll(ev: Event) {
|
||||||
const { initialScrollLeft, previousScrollLeft } = this;
|
const { initialScrollLeft, previousScrollLeft } = this;
|
||||||
const { scrollLeft, offsetWidth } = ev.target as HTMLElement;
|
const { scrollLeft, offsetWidth } = ev.target as HTMLElement;
|
||||||
|
|
||||||
|
if (initialScrollLeft === undefined) {
|
||||||
|
this.initialScrollLeft = scrollLeft;
|
||||||
|
}
|
||||||
|
|
||||||
const scrollDirection = scrollLeft > previousScrollLeft ? 'right' : 'left';
|
const scrollDirection = scrollLeft > previousScrollLeft ? 'right' : 'left';
|
||||||
this.previousScrollLeft = scrollLeft;
|
this.previousScrollLeft = scrollLeft;
|
||||||
|
|
||||||
let scrollDistance = scrollLeft;
|
// If the scroll direction is left then we need to calculate where we started and subtract
|
||||||
|
// the current scrollLeft to get the distance scrolled. Otherwise, we use the scrollLeft.
|
||||||
if (scrollDirection === 'left') {
|
const scrollDistance = scrollDirection === 'left' ? initialScrollLeft! - scrollLeft : scrollLeft;
|
||||||
scrollDistance = initialScrollLeft - scrollLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit the scroll direction and distance
|
// Emit the scroll direction and distance
|
||||||
this.ionSegmentViewScroll.emit({
|
this.ionSegmentViewScroll.emit({
|
||||||
@ -59,11 +71,54 @@ export class SegmentView implements ComponentInterface {
|
|||||||
if (segment) {
|
if (segment) {
|
||||||
segment.value = segmentButton.value;
|
segment.value = segmentButton.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.resetScrollEndTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle touch start event to know when the user is actively dragging the segment view.
|
||||||
|
*/
|
||||||
@Listen('touchstart')
|
@Listen('touchstart')
|
||||||
handleTouchStart() {
|
handleScrollStart() {
|
||||||
this.initialScrollLeft = this.el.scrollLeft;
|
if (this.scrollEndTimeout) {
|
||||||
|
clearTimeout(this.scrollEndTimeout);
|
||||||
|
this.scrollEndTimeout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isTouching = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle touch end event to know when the user is no longer dragging the segment view.
|
||||||
|
*/
|
||||||
|
@Listen('touchend')
|
||||||
|
handleTouchEnd() {
|
||||||
|
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 both conditions are met, reset the initial scroll position and
|
||||||
|
* emit the scroll end event.
|
||||||
|
*/
|
||||||
|
private checkForScrollEnd() {
|
||||||
|
if (!this.isTouching) {
|
||||||
|
this.ionSegmentViewScrollEnd.emit();
|
||||||
|
this.initialScrollLeft = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2043,14 +2043,20 @@ export class IonSegmentView {
|
|||||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
||||||
c.detach();
|
c.detach();
|
||||||
this.el = r.nativeElement;
|
this.el = r.nativeElement;
|
||||||
proxyOutputs(this, this.el, ['ionSegmentViewScroll']);
|
proxyOutputs(this, this.el, ['ionSegmentViewScroll', 'ionSegmentViewScrollEnd']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export declare interface IonSegmentView extends Components.IonSegmentView {
|
export declare interface IonSegmentView extends Components.IonSegmentView {
|
||||||
|
/**
|
||||||
|
* Emitted when the segment view is scrolled.
|
||||||
|
*/
|
||||||
ionSegmentViewScroll: EventEmitter<CustomEvent<{ scrollDirection: string; scrollDistance: number }>>;
|
ionSegmentViewScroll: EventEmitter<CustomEvent<{ scrollDirection: string; scrollDistance: number }>>;
|
||||||
|
/**
|
||||||
|
* Emitted when the segment view scroll has ended.
|
||||||
|
*/
|
||||||
|
ionSegmentViewScrollEnd: EventEmitter<CustomEvent<void>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1882,14 +1882,20 @@ export class IonSegmentView {
|
|||||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
||||||
c.detach();
|
c.detach();
|
||||||
this.el = r.nativeElement;
|
this.el = r.nativeElement;
|
||||||
proxyOutputs(this, this.el, ['ionSegmentViewScroll']);
|
proxyOutputs(this, this.el, ['ionSegmentViewScroll', 'ionSegmentViewScrollEnd']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export declare interface IonSegmentView extends Components.IonSegmentView {
|
export declare interface IonSegmentView extends Components.IonSegmentView {
|
||||||
|
/**
|
||||||
|
* Emitted when the segment view is scrolled.
|
||||||
|
*/
|
||||||
ionSegmentViewScroll: EventEmitter<CustomEvent<{ scrollDirection: string; scrollDistance: number }>>;
|
ionSegmentViewScroll: EventEmitter<CustomEvent<{ scrollDirection: string; scrollDistance: number }>>;
|
||||||
|
/**
|
||||||
|
* Emitted when the segment view scroll has ended.
|
||||||
|
*/
|
||||||
|
ionSegmentViewScrollEnd: EventEmitter<CustomEvent<void>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -762,7 +762,8 @@ export const IonSegmentContent = /*@__PURE__*/ defineContainer<JSX.IonSegmentCon
|
|||||||
|
|
||||||
export const IonSegmentView = /*@__PURE__*/ defineContainer<JSX.IonSegmentView>('ion-segment-view', defineIonSegmentView, [
|
export const IonSegmentView = /*@__PURE__*/ defineContainer<JSX.IonSegmentView>('ion-segment-view', defineIonSegmentView, [
|
||||||
'disabled',
|
'disabled',
|
||||||
'ionSegmentViewScroll'
|
'ionSegmentViewScroll',
|
||||||
|
'ionSegmentViewScrollEnd'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user