mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
fix: collapse behavior when releasing gesture
This commit is contained in:
@@ -6,6 +6,7 @@ import { createAnimation } from '@utils/animation/animation';
|
||||
* @param viewportOffset The offset of the element on the x-axis to locate it off-screen.
|
||||
* @param progress The progress of the animation (0 - 1).
|
||||
* @param isFinal Whether the animation is in its final state (collapsed or expanded).
|
||||
* @param isReset Whether to reset the element to its initial state.
|
||||
* @param zIndex _Optional_ The z-index to apply to the element.
|
||||
*/
|
||||
export const slidingItemAnimation = (
|
||||
@@ -13,11 +14,12 @@ export const slidingItemAnimation = (
|
||||
viewportOffset: number,
|
||||
progress: number,
|
||||
isFinal: boolean,
|
||||
isReset: boolean,
|
||||
zIndex: number | undefined
|
||||
) => {
|
||||
const styles = zIndex !== undefined ? { zIndex: `${zIndex}` } : {};
|
||||
|
||||
const animation = createAnimation()
|
||||
const swipeAnimation = createAnimation()
|
||||
.addElement(el)
|
||||
/**
|
||||
* The specific value here does not actually
|
||||
@@ -32,12 +34,28 @@ export const slidingItemAnimation = (
|
||||
{ offset: 1, transform: `translate3d(0,0,0)`, ...styles },
|
||||
]);
|
||||
|
||||
if (!isFinal) {
|
||||
animation.progressStart(true, progress);
|
||||
} else {
|
||||
animation.destroy();
|
||||
if (isReset) {
|
||||
swipeAnimation.destroy();
|
||||
|
||||
const toggleAnimation = createAnimation()
|
||||
const leaveAnimation = createAnimation()
|
||||
.addElement(el)
|
||||
.duration(300)
|
||||
.easing('ease-out')
|
||||
.beforeStyles({
|
||||
zIndex: zIndex,
|
||||
})
|
||||
.fromTo('transform', el.style.transform, `translate3d(${viewportOffset}px,0,0)`)
|
||||
.afterClearStyles(['z-index']);
|
||||
|
||||
leaveAnimation.play().then(() => leaveAnimation.destroy());
|
||||
}
|
||||
|
||||
if (!isFinal) {
|
||||
swipeAnimation.progressStart(true, progress);
|
||||
} else {
|
||||
swipeAnimation.destroy();
|
||||
|
||||
const expandAnimation = createAnimation()
|
||||
.addElement(el)
|
||||
.duration(300)
|
||||
.easing('ease-out')
|
||||
@@ -48,6 +66,6 @@ export const slidingItemAnimation = (
|
||||
.fromTo('transform', el.style.transform, `translate3d(0,0,0)`)
|
||||
.afterClearStyles(['z-index']);
|
||||
|
||||
toggleAnimation.play();
|
||||
expandAnimation.play();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -454,7 +454,7 @@ export class ItemSliding implements ComponentInterface {
|
||||
return;
|
||||
}
|
||||
|
||||
const { el, optsWidthRightSide, optsWidthLeftSide } = this;
|
||||
const { el, optsWidthRightSide, optsWidthLeftSide, animationType } = this;
|
||||
|
||||
const rtl = isRTL(el);
|
||||
|
||||
@@ -501,44 +501,16 @@ export class ItemSliding implements ComponentInterface {
|
||||
|
||||
openSlidingItem = undefined;
|
||||
style.transform = '';
|
||||
|
||||
if (animationType === 'modern') {
|
||||
this.animateSlidingItemOptions(0, rtl);
|
||||
}
|
||||
return;
|
||||
}
|
||||
style.transform = `translate3d(${-openAmount}px,0,0)`;
|
||||
|
||||
if (this.animationType === 'modern') {
|
||||
/**
|
||||
* The total width of the 'processed' options.
|
||||
* Used to calculate the offset to move each option off the
|
||||
* screen, on top of each other.
|
||||
*/
|
||||
let optionWidthOffset = 0;
|
||||
|
||||
const side = this.state === SlidingState.Start ? 'start' : 'end';
|
||||
|
||||
const options = Array.from(this.getOptions(side)?.querySelectorAll('ion-item-option') || []);
|
||||
const optsWidth = this.getOptionsWidth(side);
|
||||
|
||||
const progress = Math.abs(openAmount / optsWidth);
|
||||
|
||||
options.forEach((option, index) => {
|
||||
let isFinal = false;
|
||||
let zIndex: number | undefined;
|
||||
let viewportOffset = 0;
|
||||
|
||||
if (side === 'start') {
|
||||
viewportOffset = rtl ? -1 * (optsWidth - optionWidthOffset) : -1 * (option.clientWidth + optionWidthOffset);
|
||||
isFinal = openAmount <= -optsWidth;
|
||||
zIndex = rtl ? undefined : options.length - index;
|
||||
} else {
|
||||
viewportOffset = rtl ? optionWidthOffset + option.clientWidth : optsWidth - optionWidthOffset;
|
||||
isFinal = openAmount >= optsWidth;
|
||||
zIndex = rtl ? options.length - index : undefined;
|
||||
}
|
||||
|
||||
slidingItemAnimation(option, viewportOffset, progress, isFinal, zIndex);
|
||||
|
||||
optionWidthOffset += option.clientWidth;
|
||||
});
|
||||
if (animationType === 'modern') {
|
||||
this.animateSlidingItemOptions(openAmount, rtl);
|
||||
}
|
||||
|
||||
this.ionDrag.emit({
|
||||
@@ -547,6 +519,44 @@ export class ItemSliding implements ComponentInterface {
|
||||
});
|
||||
}
|
||||
|
||||
private animateSlidingItemOptions(openAmount: number, isRTL: boolean) {
|
||||
/**
|
||||
* The total width of the 'processed' options.
|
||||
* Used to calculate the offset to move each option off the
|
||||
* screen, on top of each other.
|
||||
*/
|
||||
let optionWidthOffset = 0;
|
||||
|
||||
const side = this.state === SlidingState.Start ? 'start' : 'end';
|
||||
|
||||
const options = Array.from(this.getOptions(side)?.querySelectorAll('ion-item-option') || []);
|
||||
const optsWidth = this.getOptionsWidth(side);
|
||||
|
||||
const progress = Math.abs(openAmount / optsWidth);
|
||||
|
||||
options.forEach((option, index) => {
|
||||
let isFinal = false;
|
||||
let zIndex: number | undefined;
|
||||
let viewportOffset = 0;
|
||||
|
||||
const isReset = openAmount === 0;
|
||||
|
||||
if (side === 'start') {
|
||||
viewportOffset = isRTL ? -1 * (optsWidth - optionWidthOffset) : -1 * (option.clientWidth + optionWidthOffset);
|
||||
isFinal = openAmount <= -optsWidth;
|
||||
zIndex = isRTL ? undefined : options.length - index;
|
||||
} else {
|
||||
viewportOffset = isRTL ? optionWidthOffset + option.clientWidth : optsWidth - optionWidthOffset;
|
||||
isFinal = openAmount >= optsWidth;
|
||||
zIndex = isRTL ? options.length - index : undefined;
|
||||
}
|
||||
|
||||
slidingItemAnimation(option, viewportOffset, progress, isFinal, isReset, zIndex);
|
||||
|
||||
optionWidthOffset += option.clientWidth;
|
||||
});
|
||||
}
|
||||
|
||||
private getSlidingRatioSync(): number {
|
||||
if (this.openAmount > 0) {
|
||||
return this.openAmount / this.optsWidthRightSide;
|
||||
|
||||
Reference in New Issue
Block a user