diff --git a/doric-android/doric/src/main/java/pub/doric/shader/ViewNode.java b/doric-android/doric/src/main/java/pub/doric/shader/ViewNode.java index 502680f9..56ba9e24 100644 --- a/doric-android/doric/src/main/java/pub/doric/shader/ViewNode.java +++ b/doric-android/doric/src/main/java/pub/doric/shader/ViewNode.java @@ -51,6 +51,7 @@ import com.github.pengfeizhou.jscore.JavaValue; import org.json.JSONObject; import java.util.LinkedList; +import java.util.WeakHashMap; import pub.doric.DoricContext; import pub.doric.DoricRegistry; @@ -77,6 +78,7 @@ public abstract class ViewNode extends DoricContextHolder { protected ViewGroup.LayoutParams mLayoutParams; private String mType; protected JSObject mFlexConfig; + private final WeakHashMap animators = new WeakHashMap<>(); public JSObject getFlexConfig() { return mFlexConfig; @@ -904,7 +906,7 @@ public abstract class ViewNode extends DoricContextHolder { return getNodeView().getPivotY() / getNodeView().getHeight(); } - private String[] animatedKeys = { + private final String[] animatedKeys = { "translationX", "translationY", "scaleX", @@ -916,7 +918,25 @@ public abstract class ViewNode extends DoricContextHolder { public void doAnimation(JSValue value, final DoricPromise promise) { Animator animator = parseAnimator(value); if (animator != null) { + String animatorId = value.asObject().getProperty("id").asString().value(); + animators.put(animatorId, animator); +// final float tx = getTranslationX(); +// final float ty = getTranslationY(); +// final float sx = getScaleX(); +// final float sy = getScaleY(); +// final float r = getRotation(); animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); +// setTranslationX(tx); +// setTranslationY(ty); +// setScaleX(sx); +// setScaleY(sy); +// setRotation(r); + promise.reject(new JavaValue("Animation cancelled")); + } + @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); @@ -931,6 +951,28 @@ public abstract class ViewNode extends DoricContextHolder { } } + @DoricMethod + public void clearAnimation(String id, final DoricPromise promise) { + Animator animator = animators.get(id); + if (animator != null) { + animator.cancel(); + promise.resolve(); + } else { + promise.reject(new JavaValue("Cannot find running animation for " + id)); + } + } + + @DoricMethod + public void cancelAnimation(String id, final DoricPromise promise) { + Animator animator = animators.get(id); + if (animator != null) { + animator.cancel(); + promise.resolve(); + } else { + promise.reject(new JavaValue("Cannot find running animation for " + id)); + } + } + private Animator parseAnimator(JSValue value) { if (!value.isObject()) { DoricLog.e("parseAnimator error"); diff --git a/doric-js/bundle/doric-lib.es5.js b/doric-js/bundle/doric-lib.es5.js index 74cb8d4e..b20cce2b 100644 --- a/doric-js/bundle/doric-lib.es5.js +++ b/doric-js/bundle/doric-lib.es5.js @@ -1380,6 +1380,7 @@ var Animation = /** @class */ (function () { this.changeables = new Map; this.duration = 0; this.fillMode = exports.FillMode.Forward; + this.id = uniqueId("Animation"); } Animation.prototype.toModel = function () { var e_1, _a; @@ -1409,7 +1410,8 @@ var Animation = /** @class */ (function () { repeatCount: this.repeatCount, repeatMode: this.repeatMode, fillMode: this.fillMode, - timingFunction: this.timingFunction + timingFunction: this.timingFunction, + id: this.id, }; }; return Animation; @@ -1480,13 +1482,13 @@ var TranslationAnimation = /** @class */ (function (_super) { var _this = _super.call(this) || this; _this.translationXChangeable = { key: "translationX", - fromValue: 1, - toValue: 1, + fromValue: 0, + toValue: 0, }; _this.translationYChangeable = { key: "translationY", - fromValue: 1, - toValue: 1, + fromValue: 0, + toValue: 0, }; _this.changeables.set("translationX", _this.translationXChangeable); _this.changeables.set("translationY", _this.translationYChangeable); @@ -1640,6 +1642,7 @@ var AnimationSet = /** @class */ (function () { function AnimationSet() { this.animations = []; this._duration = 0; + this.id = uniqueId("AnimationSet"); } AnimationSet.prototype.addAnimation = function (anim) { this.animations.push(anim); @@ -1661,6 +1664,7 @@ var AnimationSet = /** @class */ (function () { return e.toModel(); }), delay: this.delay, + id: this.id, }; }; return AnimationSet; diff --git a/doric-js/bundle/doric-lib.js b/doric-js/bundle/doric-lib.js index 515dbaad..04db52d7 100644 --- a/doric-js/bundle/doric-lib.js +++ b/doric-js/bundle/doric-lib.js @@ -314,6 +314,15 @@ class View { } }); } + cancelAnimation(context, animation) { + return this.nativeChannel(context, "cancelAnimation")(animation.id).then(() => { + this.__dirty_props__.translationX = this.translationX || 0; + this.__dirty_props__.translationY = this.translationY || 0; + this.__dirty_props__.scaleX = this.scaleX || 1; + this.__dirty_props__.scaleY = this.scaleY || 1; + this.__dirty_props__.rotation = this.rotation || 0; + }); + } } __decorate$d([ Property, @@ -1051,6 +1060,7 @@ class Animation { this.changeables = new Map; this.duration = 0; this.fillMode = exports.FillMode.Forward; + this.id = uniqueId("Animation"); } toModel() { const changeables = []; @@ -1069,7 +1079,8 @@ class Animation { repeatCount: this.repeatCount, repeatMode: this.repeatMode, fillMode: this.fillMode, - timingFunction: this.timingFunction + timingFunction: this.timingFunction, + id: this.id, }; } } @@ -1119,13 +1130,13 @@ class TranslationAnimation extends Animation { super(); this.translationXChangeable = { key: "translationX", - fromValue: 1, - toValue: 1, + fromValue: 0, + toValue: 0, }; this.translationYChangeable = { key: "translationY", - fromValue: 1, - toValue: 1, + fromValue: 0, + toValue: 0, }; this.changeables.set("translationX", this.translationXChangeable); this.changeables.set("translationY", this.translationYChangeable); @@ -1228,6 +1239,7 @@ class AnimationSet { constructor() { this.animations = []; this._duration = 0; + this.id = uniqueId("AnimationSet"); } addAnimation(anim) { this.animations.push(anim); @@ -1245,6 +1257,7 @@ class AnimationSet { return e.toModel(); }), delay: this.delay, + id: this.id, }; } } diff --git a/doric-js/bundle/doric-vm.js b/doric-js/bundle/doric-vm.js index 8e975120..c2727206 100644 --- a/doric-js/bundle/doric-vm.js +++ b/doric-js/bundle/doric-vm.js @@ -1835,6 +1835,15 @@ class View { } }); } + cancelAnimation(context, animation) { + return this.nativeChannel(context, "cancelAnimation")(animation.id).then(() => { + this.__dirty_props__.translationX = this.translationX || 0; + this.__dirty_props__.translationY = this.translationY || 0; + this.__dirty_props__.scaleX = this.scaleX || 1; + this.__dirty_props__.scaleY = this.scaleY || 1; + this.__dirty_props__.rotation = this.rotation || 0; + }); + } } __decorate$d([ Property, @@ -2572,6 +2581,7 @@ class Animation { this.changeables = new Map; this.duration = 0; this.fillMode = exports.FillMode.Forward; + this.id = uniqueId("Animation"); } toModel() { const changeables = []; @@ -2590,7 +2600,8 @@ class Animation { repeatCount: this.repeatCount, repeatMode: this.repeatMode, fillMode: this.fillMode, - timingFunction: this.timingFunction + timingFunction: this.timingFunction, + id: this.id, }; } } @@ -2640,13 +2651,13 @@ class TranslationAnimation extends Animation { super(); this.translationXChangeable = { key: "translationX", - fromValue: 1, - toValue: 1, + fromValue: 0, + toValue: 0, }; this.translationYChangeable = { key: "translationY", - fromValue: 1, - toValue: 1, + fromValue: 0, + toValue: 0, }; this.changeables.set("translationX", this.translationXChangeable); this.changeables.set("translationY", this.translationYChangeable); @@ -2749,6 +2760,7 @@ class AnimationSet { constructor() { this.animations = []; this._duration = 0; + this.id = uniqueId("AnimationSet"); } addAnimation(anim) { this.animations.push(anim); @@ -2766,6 +2778,7 @@ class AnimationSet { return e.toModel(); }), delay: this.delay, + id: this.id, }; } } diff --git a/doric-js/index.d.ts b/doric-js/index.d.ts index cd9a58da..8d1b31c2 100644 --- a/doric-js/index.d.ts +++ b/doric-js/index.d.ts @@ -298,6 +298,7 @@ declare module 'doric/lib/src/ui/view' { */ flexConfig?: FlexConfig; doAnimation(context: BridgeContext, animation: IAnimation): Promise; + cancelAnimation(context: BridgeContext, animation: IAnimation): Promise; } export abstract class Superview extends View { subviewById(id: string): View | undefined; @@ -326,6 +327,7 @@ declare module 'doric/lib/src/ui/animation' { export interface IAnimation extends Modeling { duration: number; delay?: number; + id: string; } export interface Changeable { fromValue: number; @@ -382,6 +384,7 @@ declare module 'doric/lib/src/ui/animation' { delay?: number; fillMode: FillMode; timingFunction?: TimingFunction; + id: string; toModel(): { type: string; delay: number | undefined; @@ -395,6 +398,7 @@ declare module 'doric/lib/src/ui/animation' { repeatMode: RepeatMode | undefined; fillMode: FillMode; timingFunction: TimingFunction | undefined; + id: string; }; } export class ScaleAnimation extends Animation { @@ -442,12 +446,14 @@ declare module 'doric/lib/src/ui/animation' { } export class AnimationSet implements IAnimation { delay?: number; + id: string; addAnimation(anim: IAnimation): void; get duration(): number; set duration(v: number); toModel(): { animations: Model; delay: number | undefined; + id: string; }; } export {}; diff --git a/doric-js/lib/src/ui/animation.d.ts b/doric-js/lib/src/ui/animation.d.ts index 19874d88..da9d8f65 100644 --- a/doric-js/lib/src/ui/animation.d.ts +++ b/doric-js/lib/src/ui/animation.d.ts @@ -7,6 +7,7 @@ export declare enum RepeatMode { export interface IAnimation extends Modeling { duration: number; delay?: number; + id: string; } export interface Changeable { fromValue: number; @@ -63,6 +64,7 @@ declare abstract class Animation implements IAnimation { delay?: number; fillMode: FillMode; timingFunction?: TimingFunction; + id: string; toModel(): { type: string; delay: number | undefined; @@ -76,6 +78,7 @@ declare abstract class Animation implements IAnimation { repeatMode: RepeatMode | undefined; fillMode: FillMode; timingFunction: TimingFunction | undefined; + id: string; }; } export declare class ScaleAnimation extends Animation { @@ -132,12 +135,14 @@ export declare class AnimationSet implements IAnimation { private animations; private _duration; delay?: number; + id: string; addAnimation(anim: IAnimation): void; get duration(): number; set duration(v: number); toModel(): { animations: Model; delay: number | undefined; + id: string; }; } export {}; diff --git a/doric-js/lib/src/ui/animation.js b/doric-js/lib/src/ui/animation.js index 94514aea..cf8c8160 100644 --- a/doric-js/lib/src/ui/animation.js +++ b/doric-js/lib/src/ui/animation.js @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { uniqueId } from "../util/uniqueId"; export var RepeatMode; (function (RepeatMode) { RepeatMode[RepeatMode["RESTART"] = 1] = "RESTART"; @@ -65,6 +66,7 @@ class Animation { this.changeables = new Map; this.duration = 0; this.fillMode = FillMode.Forward; + this.id = uniqueId("Animation"); } toModel() { const changeables = []; @@ -83,7 +85,8 @@ class Animation { repeatCount: this.repeatCount, repeatMode: this.repeatMode, fillMode: this.fillMode, - timingFunction: this.timingFunction + timingFunction: this.timingFunction, + id: this.id, }; } } @@ -133,13 +136,13 @@ export class TranslationAnimation extends Animation { super(); this.translationXChangeable = { key: "translationX", - fromValue: 1, - toValue: 1, + fromValue: 0, + toValue: 0, }; this.translationYChangeable = { key: "translationY", - fromValue: 1, - toValue: 1, + fromValue: 0, + toValue: 0, }; this.changeables.set("translationX", this.translationXChangeable); this.changeables.set("translationY", this.translationYChangeable); @@ -242,6 +245,7 @@ export class AnimationSet { constructor() { this.animations = []; this._duration = 0; + this.id = uniqueId("AnimationSet"); } addAnimation(anim) { this.animations.push(anim); @@ -259,6 +263,7 @@ export class AnimationSet { return e.toModel(); }), delay: this.delay, + id: this.id, }; } } diff --git a/doric-js/lib/src/ui/view.d.ts b/doric-js/lib/src/ui/view.d.ts index afdf4009..a1fd4c36 100644 --- a/doric-js/lib/src/ui/view.d.ts +++ b/doric-js/lib/src/ui/view.d.ts @@ -130,6 +130,7 @@ export declare abstract class View implements Modeling { */ flexConfig?: FlexConfig; doAnimation(context: BridgeContext, animation: IAnimation): Promise; + cancelAnimation(context: BridgeContext, animation: IAnimation): Promise; } export declare abstract class Superview extends View { subviewById(id: string): View | undefined; diff --git a/doric-js/lib/src/ui/view.js b/doric-js/lib/src/ui/view.js index a5b2e9cc..0d4c6e05 100644 --- a/doric-js/lib/src/ui/view.js +++ b/doric-js/lib/src/ui/view.js @@ -199,6 +199,15 @@ export class View { } }); } + cancelAnimation(context, animation) { + return this.nativeChannel(context, "cancelAnimation")(animation.id).then(() => { + this.__dirty_props__.translationX = this.translationX || 0; + this.__dirty_props__.translationY = this.translationY || 0; + this.__dirty_props__.scaleX = this.scaleX || 1; + this.__dirty_props__.scaleY = this.scaleY || 1; + this.__dirty_props__.rotation = this.rotation || 0; + }); + } } __decorate([ Property, diff --git a/doric-js/src/ui/animation.ts b/doric-js/src/ui/animation.ts index c0ebffcf..0dfb41f4 100644 --- a/doric-js/src/ui/animation.ts +++ b/doric-js/src/ui/animation.ts @@ -15,6 +15,7 @@ */ import { Modeling, Model } from "../util/types" +import { uniqueId } from "../util/uniqueId" export type AnimatedKey = "translationX" | "translationY" | "scaleX" | "scaleY" | "rotation" | "pivotX" | "pivotY" | "rotationX" | "rotationY" @@ -26,6 +27,7 @@ export enum RepeatMode { export interface IAnimation extends Modeling { duration: number delay?: number + id: string } export interface Changeable { @@ -85,6 +87,7 @@ abstract class Animation implements IAnimation { delay?: number fillMode = FillMode.Forward timingFunction?: TimingFunction + id = uniqueId("Animation") toModel() { const changeables = [] for (let e of this.changeables.values()) { @@ -102,7 +105,8 @@ abstract class Animation implements IAnimation { repeatCount: this.repeatCount, repeatMode: this.repeatMode, fillMode: this.fillMode, - timingFunction: this.timingFunction + timingFunction: this.timingFunction, + id: this.id, } } } @@ -160,13 +164,13 @@ export class ScaleAnimation extends Animation { export class TranslationAnimation extends Animation { private translationXChangeable: Changeable = { key: "translationX", - fromValue: 1, - toValue: 1, + fromValue: 0, + toValue: 0, } private translationYChangeable: Changeable = { key: "translationY", - fromValue: 1, - toValue: 1, + fromValue: 0, + toValue: 0, } constructor() { super() @@ -292,6 +296,8 @@ export class AnimationSet implements IAnimation { private animations: IAnimation[] = [] private _duration = 0 delay?: number + id = uniqueId("AnimationSet") + addAnimation(anim: IAnimation) { this.animations.push(anim) } @@ -311,6 +317,7 @@ export class AnimationSet implements IAnimation { return e.toModel() }) as Model, delay: this.delay, + id: this.id, } } } \ No newline at end of file diff --git a/doric-js/src/ui/view.es5.ts b/doric-js/src/ui/view.es5.ts index 204bd12b..3e897347 100644 --- a/doric-js/src/ui/view.es5.ts +++ b/doric-js/src/ui/view.es5.ts @@ -342,6 +342,16 @@ export abstract class View implements Modeling { } }) } + + clearAnimation(context: BridgeContext, animation: IAnimation) { + return this.nativeChannel(context, "clearAnimation")(animation.id).then(() => { + this.__dirty_props__.translationX = this.translationX || 0 + this.__dirty_props__.translationY = this.translationY || 0 + this.__dirty_props__.scaleX = this.scaleX || 1 + this.__dirty_props__.scaleY = this.scaleY || 1 + this.__dirty_props__.rotation = this.rotation || 0 + }) + } } export abstract class Superview extends View { diff --git a/doric-js/src/ui/view.ts b/doric-js/src/ui/view.ts index 07a3f840..482aeefa 100644 --- a/doric-js/src/ui/view.ts +++ b/doric-js/src/ui/view.ts @@ -351,6 +351,20 @@ export abstract class View implements Modeling { } }) } + + clearAnimation(context: BridgeContext, animation: IAnimation) { + return this.nativeChannel(context, "clearAnimation")(animation.id).then(() => { + this.__dirty_props__.translationX = this.translationX || 0 + this.__dirty_props__.translationY = this.translationY || 0 + this.__dirty_props__.scaleX = this.scaleX || 1 + this.__dirty_props__.scaleY = this.scaleY || 1 + this.__dirty_props__.rotation = this.rotation || 0 + }) + } + + cancelAnimation(context: BridgeContext, animation: IAnimation) { + return this.nativeChannel(context, "cancelAnimation")(animation.id) + } } export abstract class Superview extends View {