mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 19:57:22 +08:00
transition improvements
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
import {CSS} from '../util/dom';
|
||||
import {CSS, raf} from '../util/dom';
|
||||
|
||||
const RENDER_DELAY = 36;
|
||||
const RENDER_DELAY = 32;
|
||||
let AnimationRegistry = {};
|
||||
|
||||
/**
|
||||
@ -17,10 +17,11 @@ let AnimationRegistry = {};
|
||||
8) Run from/to animation on elements
|
||||
9) Animations finish async
|
||||
10) Set inline styles w/ the "to" effects on elements
|
||||
11) Add after classes to elements
|
||||
12) Remove after classes from elements
|
||||
13) Call onFinish()
|
||||
14) Resolve play()'s promise
|
||||
11) Call onFinish()
|
||||
12) Wait one rAF
|
||||
13) Add after classes to elements
|
||||
14) Remove after classes from elements
|
||||
15) Resolve play()'s promise
|
||||
**/
|
||||
|
||||
export class Animation {
|
||||
@ -209,8 +210,11 @@ export class Animation {
|
||||
children[i]._onFinish();
|
||||
}
|
||||
self._onFinish();
|
||||
raf(() => {
|
||||
self._onAfter();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (this._duration > RENDER_DELAY) {
|
||||
@ -291,43 +295,48 @@ export class Animation {
|
||||
|
||||
_onFinish() {
|
||||
// after the animations have finished
|
||||
const self = this;
|
||||
let i, j, ele;
|
||||
|
||||
if (!self._isFinished) {
|
||||
self._isFinished = true;
|
||||
|
||||
if (self.playbackRate() < 0) {
|
||||
// reverse direction
|
||||
for (i = 0; i < self._el.length; i++) {
|
||||
ele = self._el[i];
|
||||
|
||||
for (j = 0; j < self._bfAdd.length; j++) {
|
||||
ele.classList.remove(self._bfAdd[j]);
|
||||
if (!this._isFinished) {
|
||||
this._isFinished = true;
|
||||
this.onFinish && this.onFinish();
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < self._bfRmv.length; j++) {
|
||||
ele.classList.add(self._bfRmv[j]);
|
||||
_onAfter() {
|
||||
// one requestAnimationFrame after onFinish happened
|
||||
let i, j, ele;
|
||||
|
||||
for (i = 0; i < this._children.length; i++) {
|
||||
this._children[i]._onAfter();
|
||||
}
|
||||
|
||||
if (this.playbackRate() < 0) {
|
||||
// reverse direction
|
||||
for (i = 0; i < this._el.length; i++) {
|
||||
ele = this._el[i];
|
||||
|
||||
for (j = 0; j < this._bfAdd.length; j++) {
|
||||
ele.classList.remove(this._bfAdd[j]);
|
||||
}
|
||||
|
||||
for (j = 0; j < this._bfRmv.length; j++) {
|
||||
ele.classList.add(this._bfRmv[j]);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// normal direction
|
||||
for (i = 0; i < self._el.length; i++) {
|
||||
ele = self._el[i];
|
||||
for (i = 0; i < this._el.length; i++) {
|
||||
ele = this._el[i];
|
||||
|
||||
for (j = 0; j < self._afAdd.length; j++) {
|
||||
ele.classList.add(self._afAdd[j]);
|
||||
for (j = 0; j < this._afAdd.length; j++) {
|
||||
ele.classList.add(this._afAdd[j]);
|
||||
}
|
||||
|
||||
for (j = 0; j < self._afRmv.length; j++) {
|
||||
ele.classList.remove(self._afRmv[j]);
|
||||
for (j = 0; j < this._afRmv.length; j++) {
|
||||
ele.classList.remove(this._afRmv[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.onFinish && self.onFinish();
|
||||
}
|
||||
}
|
||||
|
||||
pause() {
|
||||
|
@ -85,7 +85,9 @@ $content-padding: 10px !default;
|
||||
opacity: 0;
|
||||
z-index: $z-index-click-block;
|
||||
transform: translate3d(-9999px, 0px, 0px);
|
||||
overflow: hidden;
|
||||
|
||||
//background: red;
|
||||
//opacity: .3;
|
||||
}
|
||||
|
||||
.click-block-active {
|
||||
|
@ -72,10 +72,8 @@ export class Navbar {
|
||||
alignTitle() {
|
||||
// called after the navbar/title has had a moment to
|
||||
// finish rendering in their correct locations
|
||||
|
||||
const navbarEle = this._ele;
|
||||
const innerTitleEle = this._innerTtEle || (this._innerTtEle = navbarEle.querySelector('.navbar-inner-title'));
|
||||
const titleEle = this._ttEle || (this._ttEle = innerTitleEle.querySelector('ion-title'));
|
||||
const titleEle = this._ttEle || (this._ttEle = navbarEle.querySelector('ion-title'));
|
||||
|
||||
// don't bother if there's no title element
|
||||
if (!titleEle) return;
|
||||
@ -87,9 +85,8 @@ export class Navbar {
|
||||
if (titleStyle.textAlign !== 'center') return;
|
||||
|
||||
// get all the dimensions
|
||||
const titleOffsetWidth = titleEle.offsetWidth;
|
||||
const titleOffsetLeft = titleEle.offsetLeft;
|
||||
const titleOffsetRight = navbarEle.offsetWidth - (titleOffsetLeft + titleOffsetWidth);
|
||||
const titleOffsetRight = navbarEle.offsetWidth - (titleOffsetLeft + titleEle.offsetWidth);
|
||||
|
||||
let marginLeft = 0;
|
||||
let marginRight = 0;
|
||||
@ -104,6 +101,7 @@ export class Navbar {
|
||||
|
||||
if ((marginLeft || marginRight) && margin !== this._ttMargin) {
|
||||
// only do an update if it has to
|
||||
const innerTitleEle = this._innerTtEle || (this._innerTtEle = navbarEle.querySelector('.navbar-inner-title'));
|
||||
innerTitleEle.style.margin = this._ttMargin = margin;
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ ion-navbar {
|
||||
justify-content: space-between;
|
||||
order: $flex-order-toolbar-top;
|
||||
|
||||
transform: translate3d(0px, -9999px, 0px);
|
||||
transform: translate3d(100%, 0px, 0px);
|
||||
&.show-navbar {
|
||||
transform: translate3d(0px, 0px, 0px);
|
||||
}
|
||||
|
@ -122,8 +122,6 @@ export class ViewController {
|
||||
|
||||
opts.animate = (opts.animation !== 'none');
|
||||
|
||||
this.transitionStart(opts);
|
||||
|
||||
// wait for the new item to complete setup
|
||||
enteringItem.stage(() => {
|
||||
|
||||
@ -144,6 +142,13 @@ export class ViewController {
|
||||
transAnimation.duration(0);
|
||||
}
|
||||
|
||||
let duration = transAnimation.duration();
|
||||
if (duration > 64) {
|
||||
// block any clicks during the transition and provide a
|
||||
// fallback to remove the clickblock if something goes wrong
|
||||
ClickBlock(true, duration + 200);
|
||||
}
|
||||
|
||||
// start the transition
|
||||
transAnimation.play().then(() => {
|
||||
|
||||
@ -193,9 +198,6 @@ export class ViewController {
|
||||
enteringItem.shouldCache = false;
|
||||
enteringItem.willEnter();
|
||||
|
||||
// start the transition
|
||||
this.transitionStart({ animate: true });
|
||||
|
||||
// wait for the new item to complete setup
|
||||
enteringItem.stage(() => {
|
||||
|
||||
@ -283,13 +285,6 @@ export class ViewController {
|
||||
return false;
|
||||
}
|
||||
|
||||
transitionStart(opts) {
|
||||
if (opts.animate) {
|
||||
// block possible clicks during transition
|
||||
ClickBlock(true, 520);
|
||||
}
|
||||
}
|
||||
|
||||
transitionComplete() {
|
||||
|
||||
this.items.forEach((item) => {
|
||||
|
@ -63,11 +63,11 @@ class IOSTransition extends Transition {
|
||||
} else {
|
||||
// forward direction
|
||||
this.enteringView
|
||||
.from(TRANSLATEX, '99%')
|
||||
.from(TRANSLATEX, OFF_RIGHT)
|
||||
.from(OPACITY, 1);
|
||||
|
||||
this.enteringTitle
|
||||
.from(TRANSLATEX, '97%');
|
||||
.from(TRANSLATEX, OFF_RIGHT);
|
||||
|
||||
this.leavingView
|
||||
.to(TRANSLATEX, OFF_LEFT)
|
||||
|
@ -1,15 +1,9 @@
|
||||
|
||||
const CSS_CLICK_BLOCK = 'click-block-active';
|
||||
const DEFAULT_EXPIRE = 330;
|
||||
let cbEle, fallbackTimerId;
|
||||
let isShowing = false;
|
||||
|
||||
|
||||
function preventClick(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
}
|
||||
|
||||
function show(expire) {
|
||||
clearTimeout(fallbackTimerId);
|
||||
fallbackTimerId = setTimeout(hide, expire || DEFAULT_EXPIRE);
|
||||
@ -23,10 +17,6 @@ function show(expire) {
|
||||
cbEle = document.createElement('div');
|
||||
cbEle.className = 'click-block ' + CSS_CLICK_BLOCK;
|
||||
document.body.appendChild(cbEle);
|
||||
cbEle.addEventListener('touchstart', preventClick);
|
||||
cbEle.addEventListener('mousedown', preventClick);
|
||||
cbEle.addEventListener('pointerdown', preventClick);
|
||||
cbEle.addEventListener('MSPointerDown', preventClick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user