App Inventor插件开发(三)动画插件

0.前言

现在已经可以写自己的插件啦!想想就好激动。
App Inventor有个很严重的缺点,那就是不支持动画。
这是个很严重的大问题,我们可以考虑通过插件解决。

1.开发

1.1预备知识

大家必须要先学好Android,不然接下来可没得玩。
在Android下,有一个View.animate()的动画实现方式,超简洁
比如我让textView在2000ms内旋转720°

textView.animate().rotation(720).setDuration(2000).start();

接下来我们将封装成一个类AnimationUtil来执行动画。

1.2创建java文件

这次的代码可能有点长,不过全是封装,看一眼就好。
老规矩,我的包是cn.roger.animation,那么我就在\components\src\cn\roger\animation下创建我的AnimationUtil.java文件

package cn.roger.animation;

import com.google.appinventor.components.annotations.*;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.*;
import com.google.appinventor.components.runtime.util.*;
import com.google.appinventor.components.runtime.errors.YailRuntimeError;
import android.view.ViewPropertyAnimator;

@DesignerComponent(version = AnimationUtil.VERSION,
    description = "by Roger Young",
    category = ComponentCategory.EXTENSION,
    nonVisible = true,
    iconName = "images/extension.png")

@SimpleObject(external = true)

public class AnimationUtil extends AndroidNonvisibleComponent {
    public static final int VERSION = 1;
    private static final String LOG_TAG = "AnimationUtil";

    public AnimationUtil(ComponentContainer container) {
        super(container.$form());
    }
    @SimpleFunction(description = "start")
    public void start(Object vpa) {
        ((ViewPropertyAnimator)vpa).start();
    }

    @SimpleFunction(description = "getAnimator")
    public Object getAnimator(AndroidViewComponent avc) {
        return avc.getView().animate();
    }

    @SimpleFunction(description = "scaleX")
    public Object scaleX(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).scaleX(f);
    }
    @SimpleFunction(description = "scaleY")
    public Object scaleY(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).scaleY(f);
    }
    @SimpleFunction(description = "scaleXBy")
    public Object scaleXBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).scaleXBy(f);
    }
    @SimpleFunction(description = "scaleYBy")
    public Object scaleYBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).scaleYBy(f);
    }

    @SimpleFunction(description = "alpha")
    public Object alpha(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).alpha(f);
    }
    @SimpleFunction(description = "alphaBy")
    public Object alphaBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).alphaBy(f);
    }

    @SimpleFunction(description = "translationX")
    public Object translationX(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).translationX(f);
    }
    @SimpleFunction(description = "translationY")
    public Object translationY(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).translationY(f);
    }
    @SimpleFunction(description = "translationZ")
    public Object translationZ(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).translationZ(f);
    }
    @SimpleFunction(description = "translationXBy")
    public Object translationXBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).translationXBy(f);
    }
    @SimpleFunction(description = "translationYBy")
    public Object translationYBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).translationYBy(f);
    }
    @SimpleFunction(description = "translationZBy")
    public Object translationZBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).translationZBy(f);
    }

    @SimpleFunction(description = "setDuration")
    public Object setDuration(Object vpa,long l) {
        return ((ViewPropertyAnimator)vpa).setDuration(l);
    }

    @SimpleFunction(description = "setStartDelay")
    public Object setStartDelay(Object vpa,long l) {
        return ((ViewPropertyAnimator)vpa).setStartDelay(l);
    }

    @SimpleFunction(description = "cancel")
    public void cancel(Object vpa) {
        ((ViewPropertyAnimator)vpa).cancel();
    }

    @SimpleFunction(description = "rotation")
    public Object rotation(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).rotation(f);
    }
    @SimpleFunction(description = "rotationX")
    public Object rotationX(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).rotationX(f);
    }
    @SimpleFunction(description = "rotationY")
    public Object rotationY(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).rotationY(f);
    }
    @SimpleFunction(description = "rotationBy")
    public Object rotationBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).rotationBy(f);
    }
    @SimpleFunction(description = "rotationXBy")
    public Object rotationXBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).rotationXBy(f);
    }
    @SimpleFunction(description = "rotationYBy")
    public Object rotationYBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).rotationYBy(f);
    }

    @SimpleFunction(description = "withLayer")
    public Object withLayer(Object vpa) {
        return ((ViewPropertyAnimator)vpa).withLayer();
    }

    @SimpleFunction(description = "x")
    public Object x(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).x(f);
    }
    @SimpleFunction(description = "y")
    public Object y(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).y(f);
    }
    @SimpleFunction(description = "z")
    public Object z(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).z(f);
    }
    @SimpleFunction(description = "xBy")
    public Object xBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).xBy(f);
    }
    @SimpleFunction(description = "yBy")
    public Object yBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).yBy(f);
    }
    @SimpleFunction(description = "zBy")
    public Object zBy(Object vpa,float f) {
        return ((ViewPropertyAnimator)vpa).zBy(f);
    }

}

1.3源码讲解

getAnimator()返回动画类ViewPropertyAnimator
start()执行,cancel()取消
剩下的方法就都是封装而已
但这里有个坑,细心的朋友可能发现了,我的返回值的类型都是Object,不是ViewPropertyAnimator。到时候用的是后还得强制类型转换,很烦。
如果你不转的话,会挂,报错

[javac] java.lang.RuntimeException: Cannot convert Java type 'android.view.ViewPropertyAnimator' to Yail type

Yail type是何方神圣我也不太清楚,顺着报错来到了\components\src\com\google\appinventor\components\scripts\ComponentProcessor.java的1500行左右,发现了以下代码

protected final String javaTypeToYailType(String type) {
  // boolean -> boolean
  if (type.equals("boolean")) {
    return type;
  }
  // String -> text
  if (type.equals("java.lang.String")) {
    return "text";
  }
  // {float, double, int, short, long, byte} -> number
  if (type.equals("float") || type.equals("double") || type.equals("int") ||
      type.equals("short") || type.equals("long") || type.equals("byte")) {
    return "number";
  }
  // YailList -> list
  if (type.equals("com.google.appinventor.components.runtime.util.YailList")) {
    return "list";
  }
  // List<?> -> list
  if (type.startsWith("java.util.List")) {
    return "list";
  }

  // Calendar -> InstantInTime
  if (type.equals("java.util.Calendar")) {
    return "InstantInTime";
  }

  if (type.equals("java.lang.Object")) {
    return "any";
  }

  if (type.equals("com.google.appinventor.components.runtime.Component")) {
    return "component";
  }

  // Check if it's a component.
  if (componentTypes.contains(type)) {
    return "component";
  }

  throw new RuntimeException("Cannot convert Java type '" + type +
                             "' to Yail type");
}

这个似乎只支持Object,于是把全部的都改成Object,再添一个强制类型转换,问题解决。
说好的any呢???

2.测试

编译导入拖入,我们先不表,来看这蛋疼的动画设置方式
还是上次的temp测试,刚才的插件都没撤掉
这里写图片描述
然后编译,运行,记得输入数字!!!不然又崩了,这就是懒的结果。。。
上成果
这里写图片描述
当你第二次点击的时候它不会动,这是因为用的是不加By的函数。加by的意思是从原先开始。
如果你不加by,那么他会从0~720,第二次是720~720,当然不会动啦
如果你加by,会从0~720,720~1440,一直增加下去。
就这样,第一个有实用功能的插件完成啦
如果大家喜欢,我不需要物质上的鼓励,在评论区里留个谢谢也行啊。毕竟我还是个高二生,需要大家的鼓励

猜你喜欢

转载自blog.csdn.net/aiw_prton/article/details/81451897