mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-21 04:53:58 +08:00
fix(animation): improve menu and go back swipe
This commit is contained in:
@ -13,6 +13,7 @@ export class Animation {
|
|||||||
private _fx: EffectProperty[];
|
private _fx: EffectProperty[];
|
||||||
private _dur: number = null;
|
private _dur: number = null;
|
||||||
private _es: string = null;
|
private _es: string = null;
|
||||||
|
private _rvEs: string = null;
|
||||||
private _bfSty: { [property: string]: any; };
|
private _bfSty: { [property: string]: any; };
|
||||||
private _bfAdd: string[];
|
private _bfAdd: string[];
|
||||||
private _bfRm: string[];
|
private _bfRm: string[];
|
||||||
@ -114,6 +115,9 @@ export class Animation {
|
|||||||
* not have an easing, then it'll get the easing from its parent.
|
* not have an easing, then it'll get the easing from its parent.
|
||||||
*/
|
*/
|
||||||
getEasing(): string {
|
getEasing(): string {
|
||||||
|
if (this._rv && this._rvEs) {
|
||||||
|
return this._rvEs;
|
||||||
|
}
|
||||||
return this._es !== null ? this._es : (this.parent && this.parent.getEasing()) || null;
|
return this._es !== null ? this._es : (this.parent && this.parent.getEasing()) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +129,14 @@ export class Animation {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the easing for this reversed animation.
|
||||||
|
*/
|
||||||
|
easingReverse(name: string): Animation {
|
||||||
|
this._rvEs = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the "from" value for a specific property.
|
* Add the "from" value for a specific property.
|
||||||
*/
|
*/
|
||||||
@ -996,14 +1008,15 @@ export class Animation {
|
|||||||
/**
|
/**
|
||||||
* End the progress animation.
|
* End the progress animation.
|
||||||
*/
|
*/
|
||||||
progressEnd(shouldComplete: boolean, currentStepValue: number, maxDelta: number = 0) {
|
progressEnd(shouldComplete: boolean, currentStepValue: number, dur: number = -1) {
|
||||||
console.debug('Animation, progressEnd, shouldComplete', shouldComplete, 'currentStepValue', currentStepValue);
|
console.debug('Animation, progressEnd, shouldComplete', shouldComplete, 'currentStepValue', currentStepValue);
|
||||||
|
|
||||||
this._isAsync = (currentStepValue > 0.05 && currentStepValue < 0.95);
|
|
||||||
|
|
||||||
const stepValue = shouldComplete ? 1 : 0;
|
const stepValue = shouldComplete ? 1 : 0;
|
||||||
const factor = Math.max(Math.abs(currentStepValue - stepValue), 0.5) * 2;
|
|
||||||
const dur = 64 + factor * maxDelta;
|
if (dur < 0) {
|
||||||
|
dur = this._dur;
|
||||||
|
}
|
||||||
|
this._isAsync = (currentStepValue > 0.05 && currentStepValue < 0.95 && dur > 30);
|
||||||
|
|
||||||
this._progressEnd(shouldComplete, stepValue, dur, this._isAsync);
|
this._progressEnd(shouldComplete, stepValue, dur, this._isAsync);
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ export class MenuContentGesture extends SlideEdgeGesture {
|
|||||||
'shouldCompleteRight', shouldCompleteRight,
|
'shouldCompleteRight', shouldCompleteRight,
|
||||||
'currentStepValue', currentStepValue);
|
'currentStepValue', currentStepValue);
|
||||||
|
|
||||||
this.menu.swipeEnd(shouldCompleteLeft, shouldCompleteRight, currentStepValue);
|
this.menu.swipeEnd(shouldCompleteLeft, shouldCompleteRight, currentStepValue, velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
getElementStartPos(slide: SlideData, ev: any) {
|
getElementStartPos(slide: SlideData, ev: any) {
|
||||||
|
@ -15,10 +15,18 @@ export class MenuType {
|
|||||||
ani: Animation = new Animation();
|
ani: Animation = new Animation();
|
||||||
isOpening: boolean;
|
isOpening: boolean;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.ani
|
||||||
|
.easing('cubic-bezier(0.0, 0.0, 0.2, 1)')
|
||||||
|
.easingReverse('cubic-bezier(0.4, 0.0, 0.6, 1)')
|
||||||
|
.duration(280);
|
||||||
|
}
|
||||||
|
|
||||||
setOpen(shouldOpen: boolean, animated: boolean, done: Function) {
|
setOpen(shouldOpen: boolean, animated: boolean, done: Function) {
|
||||||
let ani = this.ani
|
let ani = this.ani
|
||||||
.onFinish(done, true)
|
.onFinish(done, true)
|
||||||
.reverse(!shouldOpen);
|
.reverse(!shouldOpen);
|
||||||
|
|
||||||
if (animated) {
|
if (animated) {
|
||||||
ani.play();
|
ani.play();
|
||||||
} else {
|
} else {
|
||||||
@ -40,7 +48,7 @@ export class MenuType {
|
|||||||
this.ani.progressStep(stepValue);
|
this.ani.progressStep(stepValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
setProgressEnd(shouldComplete: boolean, currentStepValue: number, done: Function) {
|
setProgressEnd(shouldComplete: boolean, currentStepValue: number, velocity: number, done: Function) {
|
||||||
let isOpen = (this.isOpening && shouldComplete);
|
let isOpen = (this.isOpening && shouldComplete);
|
||||||
if (!this.isOpening && !shouldComplete) {
|
if (!this.isOpening && !shouldComplete) {
|
||||||
isOpen = true;
|
isOpen = true;
|
||||||
@ -51,7 +59,9 @@ export class MenuType {
|
|||||||
done(isOpen);
|
done(isOpen);
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
this.ani.progressEnd(shouldComplete, currentStepValue);
|
let dur = this.ani.getDuration() / (Math.abs(velocity) + 1);
|
||||||
|
|
||||||
|
this.ani.progressEnd(shouldComplete, currentStepValue, dur);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
@ -72,11 +82,6 @@ class MenuRevealType extends MenuType {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
let openedX = (menu.width() * (menu.side === 'right' ? -1 : 1)) + 'px';
|
let openedX = (menu.width() * (menu.side === 'right' ? -1 : 1)) + 'px';
|
||||||
|
|
||||||
this.ani
|
|
||||||
.easing('ease')
|
|
||||||
.duration(250);
|
|
||||||
|
|
||||||
let contentOpen = new Animation(menu.getContentElement());
|
let contentOpen = new Animation(menu.getContentElement());
|
||||||
contentOpen.fromTo('translateX', '0px', openedX);
|
contentOpen.fromTo('translateX', '0px', openedX);
|
||||||
this.ani.add(contentOpen);
|
this.ani.add(contentOpen);
|
||||||
@ -95,10 +100,6 @@ class MenuPushType extends MenuType {
|
|||||||
constructor(menu: Menu, platform: Platform) {
|
constructor(menu: Menu, platform: Platform) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.ani
|
|
||||||
.easing('ease')
|
|
||||||
.duration(250);
|
|
||||||
|
|
||||||
let contentOpenedX: string, menuClosedX: string, menuOpenedX: string;
|
let contentOpenedX: string, menuClosedX: string, menuOpenedX: string;
|
||||||
|
|
||||||
if (menu.side === 'right') {
|
if (menu.side === 'right') {
|
||||||
@ -135,10 +136,6 @@ class MenuOverlayType extends MenuType {
|
|||||||
constructor(menu: Menu, platform: Platform) {
|
constructor(menu: Menu, platform: Platform) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.ani
|
|
||||||
.easing('ease')
|
|
||||||
.duration(250);
|
|
||||||
|
|
||||||
let closedX: string, openedX: string;
|
let closedX: string, openedX: string;
|
||||||
if (menu.side === 'right') {
|
if (menu.side === 'right') {
|
||||||
// right side
|
// right side
|
||||||
|
@ -58,6 +58,12 @@ ion-menu ion-backdrop {
|
|||||||
transform: translate3d(0, 0, 0);
|
transform: translate3d(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-content-open {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
touch-action: manipulation;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-content-open ion-pane,
|
.menu-content-open ion-pane,
|
||||||
.menu-content-open ion-content,
|
.menu-content-open ion-content,
|
||||||
.menu-content-open .toolbar {
|
.menu-content-open .toolbar {
|
||||||
|
@ -465,7 +465,7 @@ export class Menu {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
swipeEnd(shouldCompleteLeft: boolean, shouldCompleteRight: boolean, stepValue: number) {
|
swipeEnd(shouldCompleteLeft: boolean, shouldCompleteRight: boolean, stepValue: number, velocity: number) {
|
||||||
if (!this._isAnimating) {
|
if (!this._isAnimating) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -478,7 +478,7 @@ export class Menu {
|
|||||||
shouldComplete = (this.side === 'right') ? shouldCompleteRight : shouldCompleteLeft;
|
shouldComplete = (this.side === 'right') ? shouldCompleteRight : shouldCompleteLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._getType().setProgressEnd(shouldComplete, stepValue, (isOpen: boolean) => {
|
this._getType().setProgressEnd(shouldComplete, stepValue, velocity, (isOpen: boolean) => {
|
||||||
console.debug('menu, swipeEnd', this.side);
|
console.debug('menu, swipeEnd', this.side);
|
||||||
this._after(isOpen);
|
this._after(isOpen);
|
||||||
});
|
});
|
||||||
@ -512,14 +512,9 @@ export class Menu {
|
|||||||
|
|
||||||
this._cntEle.classList.add('menu-content-open');
|
this._cntEle.classList.add('menu-content-open');
|
||||||
let callback = this.onBackdropClick.bind(this);
|
let callback = this.onBackdropClick.bind(this);
|
||||||
this._events.pointerEvents({
|
this._events.listen(this._cntEle, 'click', callback, true);
|
||||||
element: this._cntEle,
|
this._events.listen(this.backdrop.getNativeElement(), 'click', callback, true);
|
||||||
pointerDown: callback
|
|
||||||
});
|
|
||||||
this._events.pointerEvents({
|
|
||||||
element: this.backdrop.getNativeElement(),
|
|
||||||
pointerDown: callback
|
|
||||||
});
|
|
||||||
this.ionOpen.emit(true);
|
this.ionOpen.emit(true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -65,7 +65,7 @@ export class NavControllerBase extends Ion implements NavController {
|
|||||||
super(config, elementRef, renderer);
|
super(config, elementRef, renderer);
|
||||||
|
|
||||||
this._sbEnabled = config.getBoolean('swipeBackEnabled');
|
this._sbEnabled = config.getBoolean('swipeBackEnabled');
|
||||||
this._sbThreshold = config.getNumber('swipeBackThreshold', 40);
|
this._sbThreshold = config.getNumber('swipeBackThreshold', 0);
|
||||||
|
|
||||||
this.id = 'n' + (++ctrlIds);
|
this.id = 'n' + (++ctrlIds);
|
||||||
}
|
}
|
||||||
@ -918,10 +918,11 @@ export class NavControllerBase extends Ion implements NavController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
swipeBackEnd(shouldComplete: boolean, currentStepValue: number) {
|
swipeBackEnd(shouldComplete: boolean, currentStepValue: number, velocity: number) {
|
||||||
if (this._sbTrns && this._sbGesture) {
|
if (this._sbTrns && this._sbGesture) {
|
||||||
// the swipe back gesture has ended
|
// the swipe back gesture has ended
|
||||||
this._sbTrns.progressEnd(shouldComplete, currentStepValue, 300);
|
const dur = this._sbTrns.getDuration() / (Math.abs(velocity) + 1);
|
||||||
|
this._sbTrns.progressEnd(shouldComplete, currentStepValue, dur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,12 +53,13 @@ export class SwipeBackGesture extends SlideEdgeGesture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSlideEnd(slide: SlideData, ev: any) {
|
onSlideEnd(slide: SlideData, ev: any) {
|
||||||
|
const velocity = slide.velocity;
|
||||||
const currentStepValue = (slide.distance / slide.max);
|
const currentStepValue = (slide.distance / slide.max);
|
||||||
const isResetDirecction = slide.velocity < 0;
|
const isResetDirecction = velocity < 0;
|
||||||
const isMovingFast = Math.abs(slide.velocity) > 0.4;
|
const isMovingFast = Math.abs(slide.velocity) > 0.4;
|
||||||
const isInResetZone = Math.abs(slide.delta) < Math.abs(slide.max) * 0.5;
|
const isInResetZone = Math.abs(slide.delta) < Math.abs(slide.max) * 0.5;
|
||||||
const shouldComplete = !swipeShouldReset(isResetDirecction, isMovingFast, isInResetZone);
|
const shouldComplete = !swipeShouldReset(isResetDirecction, isMovingFast, isInResetZone);
|
||||||
|
|
||||||
this._nav.swipeBackEnd(shouldComplete, currentStepValue);
|
this._nav.swipeBackEnd(shouldComplete, currentStepValue, velocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,6 @@ export const PLATFORM_CONFIGS: {[key: string]: PlatformConfig} = {
|
|||||||
scrollAssist: isIOS,
|
scrollAssist: isIOS,
|
||||||
statusbarPadding: isCordova,
|
statusbarPadding: isCordova,
|
||||||
swipeBackEnabled: isIOS,
|
swipeBackEnabled: isIOS,
|
||||||
swipeBackThreshold: 40,
|
|
||||||
tapPolyfill: isIOSUI,
|
tapPolyfill: isIOSUI,
|
||||||
virtualScrollEventAssist: isIOSUI,
|
virtualScrollEventAssist: isIOSUI,
|
||||||
disableScrollAssist: isIOS,
|
disableScrollAssist: isIOS,
|
||||||
|
Reference in New Issue
Block a user