diff --git a/Android/doric/src/main/java/pub/doric/shader/ViewNode.java b/Android/doric/src/main/java/pub/doric/shader/ViewNode.java index be0173ff..a92a7cd5 100644 --- a/Android/doric/src/main/java/pub/doric/shader/ViewNode.java +++ b/Android/doric/src/main/java/pub/doric/shader/ViewNode.java @@ -16,12 +16,13 @@ package pub.doric.shader; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -29,16 +30,18 @@ import android.widget.LinearLayout; import androidx.annotation.NonNull; -import pub.doric.Doric; import pub.doric.DoricContext; import pub.doric.DoricRegistry; import pub.doric.async.AsyncResult; import pub.doric.extension.bridge.DoricMethod; +import pub.doric.extension.bridge.DoricPromise; import pub.doric.utils.DoricContextHolder; import pub.doric.utils.DoricConstant; +import pub.doric.utils.DoricLog; import pub.doric.utils.DoricMetaInfo; import pub.doric.utils.DoricUtils; +import com.github.pengfeizhou.jscore.JSArray; import com.github.pengfeizhou.jscore.JSDecoder; import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSValue; @@ -636,4 +639,62 @@ public abstract class ViewNode extends DoricContextHolder { public float getPivotY() { return getNodeView().getPivotY() / getNodeView().getHeight(); } + + @DoricMethod + public void doAnimation(JSValue value, final DoricPromise promise) { + Animator animator = parseAnimator(value); + if (animator != null) { + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + promise.resolve(); + } + }); + animator.start(); + } + } + + private Animator parseAnimator(JSValue value) { + if (value.isArray()) { + AnimatorSet animatorSet = new AnimatorSet(); + for (int i = 0; i < value.asArray().size(); i++) { + animatorSet.play(parseAnimator(value.asArray().get(i))); + } + return animatorSet; + } else if (value.isObject()) { + JSArray changeables = value.asObject().getProperty("changeables").asArray(); + AnimatorSet animatorSet = new AnimatorSet(); + for (int j = 0; j < changeables.size(); j++) { + animatorSet.play(parseChangeable(changeables.get(j).asObject())); + } + long duration = value.asObject().getProperty("duration").asNumber().toLong(); + animatorSet.setDuration(duration); + JSValue delayJS = value.asObject().getProperty("delay"); + if (delayJS.isNumber()) { + animatorSet.setStartDelay(delayJS.asNumber().toLong()); + } + return animatorSet; + } else { + return null; + } + } + + private Animator parseChangeable(JSObject jsObject) { + String key = jsObject.getProperty("key").asString().value(); + ObjectAnimator animator = ObjectAnimator.ofFloat(this, + key, + jsObject.getProperty("fromValue").asNumber().toFloat(), + jsObject.getProperty("toValue").asNumber().toFloat() + ); + JSValue repeatCount = jsObject.getProperty("repeatCount"); + if (repeatCount.isNumber()) { + animator.setRepeatCount(repeatCount.asNumber().toInt() + 1); + } + JSValue repeatMode = jsObject.getProperty("repeatMode"); + if (repeatMode.isNumber()) { + animator.setRepeatMode(repeatMode.asNumber().toInt()); + } + return animator; + } } diff --git a/demo/src/AnimatorDemo.ts b/demo/src/AnimatorDemo.ts index 27dca175..7e87b27c 100644 --- a/demo/src/AnimatorDemo.ts +++ b/demo/src/AnimatorDemo.ts @@ -1,4 +1,4 @@ -import { animate, Group, Panel, gravity, Color, LayoutSpec, vlayout, scroller, layoutConfig, IVLayout, modal, IText, network, View, stack, IHLayout, hlayout, IView, text } from "doric"; +import { animate, Group, Panel, gravity, Color, AnimationSet, vlayout, scroller, layoutConfig, IVLayout, modal, IText, network, View, stack, IHLayout, hlayout, IView, text, TranslationAnimation, ScaleAnimation, RotationAnimation } from "doric"; import { title, colors, box } from "./utils"; function thisLabel(str: string) { @@ -164,6 +164,36 @@ class AnimatorDemo extends Panel { }); } }), + thisLabel('animationSet').apply({ + onClick: () => { + const animationSet = new AnimationSet + + const translate = new TranslationAnimation + translate.fromTranslationX = 10 + translate.toTranslationX = 200 + translate.fromTranslationY = 10 + translate.toTranslationY = 200 + translate.duration = 1000 + + const scale = new ScaleAnimation + scale.fromScaleX = 1 + scale.toScaleX = 5 + scale.fromScaleY = 1 + scale.toScaleY = 5 + scale.duration = 1000 + + const rotation = new RotationAnimation + rotation.fromRotation = 0 + rotation.toRotation = 6 + rotation.duration = 1000 + + animationSet.addAnimation(translate) + animationSet.addAnimation(scale) + animationSet.addAnimation(rotation) + + view.doAnimation(context, animationSet) + } + }), ]).apply({ space: 10 } as IHLayout), ] ).apply({ space: 10 } as IVLayout), diff --git a/js-framework/src/ui/animation.ts b/js-framework/src/ui/animation.ts index 2b0e43bd..15fea10a 100644 --- a/js-framework/src/ui/animation.ts +++ b/js-framework/src/ui/animation.ts @@ -19,12 +19,10 @@ import { Modeling, Model } from "../util/types" export type AnimatedKey = "translationX" | "translationY" | "scaleX" | "scaleY" | "rotation" | "pivotX" | "pivotY" export enum RepeatMode { - RESTART, - REVERSE, + RESTART = 1, + REVERSE = 2, } export interface IAnimation extends Modeling { - repeatCount?: number - repeatMode?: RepeatMode duration: number delay?: number } @@ -33,6 +31,8 @@ export interface Changeable { fromValue: number toValue: number key: AnimatedKey + repeatCount?: number + repeatMode?: RepeatMode } abstract class Animation implements IAnimation { @@ -43,24 +43,27 @@ abstract class Animation implements IAnimation { delay?: number toModel() { - const ret = [] + const changeables = [] for (let e of this.changeables.values()) { - ret.push({ - repeatCount: this.repeatCount, - repeatMode: this.repeatMode, - delay: this.delay, - duration: this.duration, + changeables.push({ key: e.key, fromValue: e.fromValue, toValue: e.toValue, + repeatCount: this.repeatCount, + repeatMode: this.repeatMode, }) } - return ret + return { + type: this.constructor.name, + delay: this.delay, + duration: this.duration, + changeables, + } } } export class ScaleAnimation extends Animation { - private scaleXChaneable: Changeable = { + private scaleXChangeable: Changeable = { key: "scaleX", fromValue: 1, toValue: 1, @@ -72,25 +75,25 @@ export class ScaleAnimation extends Animation { } constructor() { super() - this.changeables.set("scaleX", this.scaleXChaneable) - this.changeables.set("scaleY", this.scaleXChaneable) + this.changeables.set("scaleX", this.scaleXChangeable) + this.changeables.set("scaleY", this.scaleYChangeable) } set fromScaleX(v: number) { - this.scaleXChaneable.fromValue = v + this.scaleXChangeable.fromValue = v } get fromScaleX() { - return this.scaleXChaneable.fromValue + return this.scaleXChangeable.fromValue } set toScaleX(v: number) { - this.scaleXChaneable.toValue = v + this.scaleXChangeable.toValue = v } get toScaleX() { - return this.scaleXChaneable.toValue + return this.scaleXChangeable.toValue } set fromScaleY(v: number) { this.scaleYChangeable.fromValue = v @@ -186,14 +189,15 @@ export class RotationAnimation extends Animation { } } -export class AnimaionSet implements IAnimation { - animations: IAnimation[] = [] +export class AnimationSet implements IAnimation { + private animations: IAnimation[] = [] _duration = 0 - - repeatCount?: number - repeatMode?: RepeatMode delay?: number + addAnimation(anim: IAnimation) { + this.animations.push(anim) + } + get duration() { return this._duration } diff --git a/js-framework/src/ui/view.ts b/js-framework/src/ui/view.ts index bc399242..ee300022 100644 --- a/js-framework/src/ui/view.ts +++ b/js-framework/src/ui/view.ts @@ -336,7 +336,7 @@ export abstract class View implements Modeling, IView { /**----------transform----------*/ doAnimation(context: BridgeContext, animation: IAnimation) { - return this.nativeChannel(context, "doAnimation")(animation) + return this.nativeChannel(context, "doAnimation")(animation.toModel()) } }