mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 03:32:21 +08:00
transition updates
This commit is contained in:
@ -9,32 +9,45 @@ const data = Collide.data;
|
|||||||
|
|
||||||
|
|
||||||
export class Animation {
|
export class Animation {
|
||||||
constructor() {
|
constructor(ele) {
|
||||||
this.parent = null;
|
this.parent = null;
|
||||||
this._elements = null;
|
|
||||||
this._options = {};
|
this._options = {};
|
||||||
this._properties = {};
|
this._properties = {};
|
||||||
this._resolve = null;
|
this._resolve = null;
|
||||||
this._call = null;
|
this._call = null;
|
||||||
|
|
||||||
this.children = [];
|
this.children = [];
|
||||||
|
|
||||||
|
this.elements(ele);
|
||||||
}
|
}
|
||||||
|
|
||||||
addChild(animation) {
|
addChild(childAnimation) {
|
||||||
animation.parent = this;
|
childAnimation.parent = this;
|
||||||
this.children.push(animation);
|
this.children.push(childAnimation);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
setChildren(childAnimations) {
|
||||||
|
for (let i = 0; i < childAnimations.length; i++) {
|
||||||
|
this.addChild(childAnimations[i]);
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
elements(ele) {
|
elements(ele) {
|
||||||
if (ele && ele.length > 0) {
|
this._ele = [];
|
||||||
this._elements = ele;
|
|
||||||
|
|
||||||
} else if (ele && ele.nodeType) {
|
if (ele) {
|
||||||
this._elements = [ele];
|
if (typeof ele === 'string') {
|
||||||
|
ele = document.querySelectorAll(ele);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
if (ele.length) {
|
||||||
this._elements = null;
|
this._ele = ele;
|
||||||
|
|
||||||
|
} else if (ele.nodeType) {
|
||||||
|
this._ele.push(ele);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -51,8 +64,8 @@ export class Animation {
|
|||||||
this.stop();
|
this.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._elements && this._elements.length) {
|
if (this._ele.length) {
|
||||||
this._promise = new Promise(res => {
|
let promise = new Promise(res => {
|
||||||
this._resolve = res;
|
this._resolve = res;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -85,35 +98,35 @@ export class Animation {
|
|||||||
|
|
||||||
var opts = util.extend({}, Collide.defaults);
|
var opts = util.extend({}, Collide.defaults);
|
||||||
|
|
||||||
if (this.parent && this.parent._options) {
|
if (this.parent) {
|
||||||
opts = util.extend(opts, this.parent._options);
|
opts = util.extend(opts, this.parent._options);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._options = util.extend(opts, this._options);
|
this._options = util.extend(opts, this._options);
|
||||||
|
|
||||||
// get the elements ready
|
// get the elements ready
|
||||||
for (var i = 0, ii = this._elements.length; i < ii; i++) {
|
for (var i = 0, ii = this._ele.length; i < ii; i++) {
|
||||||
processElement('start', this, i, clearCache);
|
processElement('start', this, i, clearCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
onNextFrame();
|
onNextFrame();
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
return promise;
|
||||||
this._promise = Promise.resolve();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
_queueAnimation() {
|
_queueAnimation() {
|
||||||
if (this._elements) {
|
if (this._ele.length) {
|
||||||
|
|
||||||
if (this._call === null) {
|
if (this._call === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var eleData;
|
var eleData;
|
||||||
for (var i = 0, ii = this._elements.length, element; i < ii && (element = this._elements[i]); i++) {
|
for (var i = 0, ii = this._ele.length, element; i < ii && (element = this._ele[i]); i++) {
|
||||||
if (element) {
|
if (element) {
|
||||||
eleData = data(element);
|
eleData = data(element);
|
||||||
if (eleData) {
|
if (eleData) {
|
||||||
@ -141,7 +154,7 @@ export class Animation {
|
|||||||
/* Add the current call plus its associated metadata (the element set and the call's options) onto the global call container.
|
/* Add the current call plus its associated metadata (the element set and the call's options) onto the global call container.
|
||||||
Anything on this call container is subjected to tick() processing. */
|
Anything on this call container is subjected to tick() processing. */
|
||||||
Collide.State.calls.push([ this._call,
|
Collide.State.calls.push([ this._call,
|
||||||
this._elements,
|
this._ele,
|
||||||
this._options,
|
this._options,
|
||||||
null,
|
null,
|
||||||
this._resolve ]);
|
this._resolve ]);
|
||||||
@ -160,12 +173,12 @@ export class Animation {
|
|||||||
|
|
||||||
var clearCache = (this._aniType !== 'start');
|
var clearCache = (this._aniType !== 'start');
|
||||||
|
|
||||||
this._setupElements(clearCache, () => {
|
var promise = this._setupElements(clearCache, () => {
|
||||||
this._aniType = 'start';
|
this._aniType = 'start';
|
||||||
this._queueAnimation();
|
this._queueAnimation();
|
||||||
});
|
});
|
||||||
|
|
||||||
promises.push(this._promise);
|
promises.push(promise);
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
@ -178,25 +191,25 @@ export class Animation {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var clearCache = (this._aniType !== 'percent');
|
var clearCache = (this._aniType !== 'progress');
|
||||||
|
|
||||||
this._setupElements(clearCache, () => {
|
var promise = this._setupElements(clearCache, () => {
|
||||||
this._aniType = 'percent';
|
this._aniType = 'progress';
|
||||||
});
|
});
|
||||||
|
|
||||||
promises.push(this._promise);
|
promises.push(promise);
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
percent(percentComplete) {
|
progress(value) {
|
||||||
// go to and stop at a specific point in the animation
|
// go to and stop at a specific point in the animation
|
||||||
|
|
||||||
if (this._aniType = 'percent') {
|
if (this._aniType = 'progress') {
|
||||||
this._options.percentComplete = percentComplete;
|
this._options.percentComplete = value;
|
||||||
|
|
||||||
for (var i = 0; i < this.children.length; i++) {
|
for (var i = 0; i < this.children.length; i++) {
|
||||||
this.children[i].percent(percentComplete);
|
this.children[i].progress(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._queueAnimation();
|
this._queueAnimation();
|
||||||
@ -205,21 +218,21 @@ export class Animation {
|
|||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
// immediately stop where it's at
|
// immediately stop where it's at
|
||||||
animationStop(this._elements, 'stop');
|
animationStop(this._ele, 'stop');
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
finish() {
|
finish() {
|
||||||
// immediately go to the end of the animation
|
// immediately go to the end of the animation
|
||||||
animationStop(this._elements, 'finish');
|
animationStop(this._ele, 'finish');
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
isAnimating() {
|
isAnimating() {
|
||||||
var eleData;
|
var eleData;
|
||||||
if (this._elements) {
|
if (this._ele) {
|
||||||
for (var i = 0, ii = this._elements.length; i < ii; i++) {
|
for (var i = 0, ii = this._ele.length; i < ii; i++) {
|
||||||
eleData = data(this._elements[i]);
|
eleData = data(this._ele[i]);
|
||||||
if (eleData && eleData.isAnimating) {
|
if (eleData && eleData.isAnimating) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -242,11 +255,6 @@ export class Animation {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeOption(key) {
|
|
||||||
delete this._options[key];
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
duration(val) {
|
duration(val) {
|
||||||
this._options.duration = val;
|
this._options.duration = val;
|
||||||
return this;
|
return this;
|
||||||
@ -257,23 +265,40 @@ export class Animation {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display(val) {
|
||||||
|
this._options.display = val;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
Properties
|
Properties
|
||||||
***************/
|
***************/
|
||||||
|
|
||||||
|
from(propertyName, value) {
|
||||||
|
// [endValue, easing, startValue]
|
||||||
|
let prop = this.getProperty(propertyName);
|
||||||
|
prop[2] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
to() {
|
to() {
|
||||||
|
// [endValue, easing, startValue]
|
||||||
if (arguments.length > 1) {
|
if (arguments.length > 1) {
|
||||||
this._properties[ arguments[0] ] = arguments[1];
|
let prop = this.getProperty(arguments[0]);
|
||||||
|
prop[0] = arguments[1];
|
||||||
} else {
|
} else {
|
||||||
this._properties = arguments[0] || {};
|
this._properties = arguments[0] || {};
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeProperty(key) {
|
getProperty(propertyName) {
|
||||||
delete this._properties[key];
|
// [endValue, easing, startValue]
|
||||||
return this;
|
if (!this._properties[propertyName]) {
|
||||||
|
this._properties[propertyName] = [null, null, null];
|
||||||
|
}
|
||||||
|
return this._properties[propertyName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ const data = Collide.data;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export function processElement(action, animation, elementIndex, clearCache) {
|
export function processElement(action, animation, elementIndex, clearCache) {
|
||||||
var elements = animation._elements;
|
var elements = animation._ele;
|
||||||
var elementsLength = elements.length;
|
var elementsLength = elements.length;
|
||||||
var element = elements[elementIndex];
|
var element = elements[elementIndex];
|
||||||
|
|
||||||
@ -254,36 +254,9 @@ export function processElement(action, animation, elementIndex, clearCache) {
|
|||||||
The optional third parameter is a forcefed startValue to be used instead of querying the DOM for
|
The optional third parameter is a forcefed startValue to be used instead of querying the DOM for
|
||||||
the element's current value. */
|
the element's current value. */
|
||||||
function parsePropertyValue(valueData, skipResolvingEasing) {
|
function parsePropertyValue(valueData, skipResolvingEasing) {
|
||||||
var endValue = undefined,
|
var endValue = valueData[0];
|
||||||
easing = undefined,
|
var easing = skipResolvingEasing ? valueData[1] : getEasing(valueData[1], opts.duration);
|
||||||
startValue = undefined;
|
var startValue = valueData[2];
|
||||||
|
|
||||||
/* Handle the array format, which can be structured as one of three potential overloads:
|
|
||||||
A) [ endValue, easing, startValue ], B) [ endValue, easing ], or C) [ endValue, startValue ] */
|
|
||||||
if (Array.isArray(valueData)) {
|
|
||||||
/* endValue is always the first item in the array. Don't bother validating endValue's value now
|
|
||||||
since the ensuing property cycling logic does that. */
|
|
||||||
endValue = valueData[0];
|
|
||||||
|
|
||||||
/* Two-item array format: If the second item is a number, function, or hex string, treat it as a
|
|
||||||
start value since easings can only be non-hex strings or arrays. */
|
|
||||||
if ((!Array.isArray(valueData[1]) && /^[\d-]/.test(valueData[1])) || typeof valueData[1] === 'function' || CSS.RegEx.isHex.test(valueData[1])) {
|
|
||||||
startValue = valueData[1];
|
|
||||||
|
|
||||||
/* Two or three-item array: If the second item is a non-hex string or an array, treat it as an easing. */
|
|
||||||
} else if ((util.isString(valueData[1]) && !CSS.RegEx.isHex.test(valueData[1])) || Array.isArray(valueData[1])) {
|
|
||||||
easing = skipResolvingEasing ? valueData[1] : getEasing(valueData[1], opts.duration);
|
|
||||||
|
|
||||||
/* Don't bother validating startValue's value now since the ensuing property cycling logic inherently does that. */
|
|
||||||
if (valueData[2] !== undefined) {
|
|
||||||
startValue = valueData[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* Handle the single-value format. */
|
|
||||||
endValue = valueData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Default to the call's easing if a per-property easing type was not defined. */
|
/* Default to the call's easing if a per-property easing type was not defined. */
|
||||||
if (!skipResolvingEasing) {
|
if (!skipResolvingEasing) {
|
||||||
|
@ -1,2 +1,14 @@
|
|||||||
<ion-nav [initial]="initial">
|
<ion-nav [initial]="initial">
|
||||||
</ion-nav>
|
</ion-nav>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
ion-nav {
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
@ -6,6 +6,12 @@ import {Transition} from './transition'
|
|||||||
|
|
||||||
const EASING_FN = [.36, .66, .04, 1];
|
const EASING_FN = [.36, .66, .04, 1];
|
||||||
const DURATION = 500;
|
const DURATION = 500;
|
||||||
|
const OFF_RIGHT = '100%';
|
||||||
|
const OFF_LEFT = '-33%';
|
||||||
|
const OFF_OPACITY = 0.8;
|
||||||
|
|
||||||
|
const TRANSLATE_X = 'translateX';
|
||||||
|
const OPACITY = 'opacity';
|
||||||
|
|
||||||
|
|
||||||
class IOSTransition extends Animation {
|
class IOSTransition extends Animation {
|
||||||
@ -13,6 +19,7 @@ class IOSTransition extends Animation {
|
|||||||
constructor(navCtrl, opts) {
|
constructor(navCtrl, opts) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
// global duration and easing for all child animations
|
||||||
this.duration(DURATION);
|
this.duration(DURATION);
|
||||||
this.easing('ios');
|
this.easing('ios');
|
||||||
|
|
||||||
@ -20,30 +27,52 @@ class IOSTransition extends Animation {
|
|||||||
this.enteringItem = navCtrl.getStagedEnteringItem();
|
this.enteringItem = navCtrl.getStagedEnteringItem();
|
||||||
this.leavingItem = navCtrl.getStagedLeavingItem();
|
this.leavingItem = navCtrl.getStagedLeavingItem();
|
||||||
|
|
||||||
// create animation for entering item
|
// create animation for the entering item
|
||||||
let enteringItemAnimation = new Animation();
|
let enteringItemAnimation = new Animation(this.enteringItem.navItem.domElement);
|
||||||
enteringItemAnimation.elements(this.enteringItem.navItem.domElement);
|
|
||||||
|
|
||||||
// show the item
|
// create animation for the leaving item
|
||||||
this.enteringItem.navItem.domElement.style.display = 'block';
|
// leavingItem could be null, but the animation instance knows to do nothing
|
||||||
|
let leavingItemAnimation = new Animation(this.leavingItem && this.leavingItem.navItem.domElement);
|
||||||
|
|
||||||
|
// entering item moves to center
|
||||||
|
// before starting, set enteringItem to display: block
|
||||||
|
enteringItemAnimation
|
||||||
|
.display('block')
|
||||||
|
.to(TRANSLATE_X, 0)
|
||||||
|
.to(OPACITY, 1);
|
||||||
|
|
||||||
|
// leaving view moves off screen
|
||||||
|
// when completed, set leavingItem to display: none
|
||||||
|
leavingItemAnimation
|
||||||
|
.from(TRANSLATE_X, 0)
|
||||||
|
.from(OPACITY, 1)
|
||||||
|
.display('none');
|
||||||
|
|
||||||
|
// set properties depending on direction
|
||||||
if (opts.direction === 'back') {
|
if (opts.direction === 'back') {
|
||||||
// back direction
|
// back direction
|
||||||
this.enteringItem.navItem.domElement.style.transform = 'translateX(-33%)';
|
enteringItemAnimation
|
||||||
if (this.leavingItem) {
|
.from(TRANSLATE_X, OFF_LEFT)
|
||||||
this.leavingItem.navItem.domElement.style.display = '';
|
.from(OPACITY, OFF_OPACITY)
|
||||||
}
|
.to(OPACITY, 1);
|
||||||
|
|
||||||
|
leavingItemAnimation
|
||||||
|
.to(TRANSLATE_X, OFF_RIGHT)
|
||||||
|
.to(OPACITY, 1);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// forward direction
|
// forward direction
|
||||||
this.enteringItem.navItem.domElement.style.transform = 'translateX(100%)';
|
enteringItemAnimation
|
||||||
|
.from(TRANSLATE_X, OFF_RIGHT)
|
||||||
|
.from(OPACITY, 1);
|
||||||
|
|
||||||
|
leavingItemAnimation
|
||||||
|
.to(TRANSLATE_X, OFF_LEFT)
|
||||||
|
.to(OPACITY, OFF_OPACITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// entering item moves to dead center
|
// set child animations
|
||||||
enteringItemAnimation.to('translateX', ['0%', '100%']);
|
this.setChildren([enteringItemAnimation, leavingItemAnimation]);
|
||||||
|
|
||||||
this.addChild(enteringItemAnimation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stage() {
|
stage() {
|
||||||
|
Reference in New Issue
Block a user