持续创造,加快成长!这是我参加「日新计划 6 月更文应战」的第1天,点击检查活动详情

牙叔教程 简单易懂

正常动画速度500ms

autojs点赞按钮动画

慢速动画3秒

autojs点赞按钮动画

思路

  1. 制作布景, 白色的圆角矩形
  2. 制作爱心, 红色的心形
  3. 添加点击动画

制作白色的矩形

drawBg(that.roundRectPaint, that.fraction, canvas, that.width, that.height);

是现已封装好的代码, 便是画个圆角矩形

function drawBg(paint, fraction, canvas, width, height) {
  let left = 0;
  let top = 0;
  let right = width;
  let bottom = height;
  // scale
  let scaleX = leap(1, 0.9, 1, fraction);
  let scaleY = scaleX;
  let pivotX = width / 2;
  let pivotY = height / 2;
  canvas.scale(scaleX, scaleY, pivotX, pivotY);
  let radius = 100;
  canvas.drawRoundRect(left, top, right, bottom, radius, radius, paint);
}

其中有5个参数

function drawBg(paint, fraction, canvas, width, height)

paint是画笔

fraction是操控Canvas缩放的

canvas是画板

width, height是矩形的宽高

fraction是这里边最要害的, 由于咱们这个教程首要便是写动画;

动画的首要形式便是操控canvas的缩放

fraction首要用在leap函数里边, 咱们看看leap是什么?

leap

function leap(a, b, c, fraction) {
  if (fraction <= 0.5) {
    return MathUtils.lerp(a, b, fraction * 2);
  } else {
    let tempFraction = fraction - 0.5;
    return MathUtils.lerp(b, c, tempFraction * 2);
  }
}

leap返回一个数字, 用这个数字来操控动画;

数字是用lerp计算出来的

lerp

com.google.android.material.math.MathUtils.lerp

咱们去安卓官网看看这个办法

public static float lerp (float start,
                float stop, 
                float amount)

Returns the linear interpolation of amount between start and stop.

返回两个数字时间的线性插值

Canvas

canvas从哪里来的?

canvas是自定义控件的参数, 是onDraw的参数

CustomView.prototype.render = function () {
  let that = this;
  return JavaAdapter(
    android.view.View,
    {
      onDraw: function (canvas) {...}

咱们制作矩形和心形都是在 onDraw 办法中制作;

制作矩形的时分, 要知道矩形的宽高;

宽高要测量, 测量办法是 onMeasure

onMeasure: function (widthMeasureSpec, heightMeasureSpec) {
  this.super$onMeasure(heightMeasureSpec, widthMeasureSpec);
  this.setMeasuredDimension(this.getMeasuredHeight(), this.getMeasuredWidth());
  that.width = this.getMeasuredWidth();
  that.height = this.getMeasuredHeight();
},onMeasure: function (widthMeasureSpec, heightMeasureSpec) {

心形

制作完矩形, 咱们要制作心形;

心形运用的是内置icon,

let drawableId = "ic_favorite_black_48dp";
let imgId = resources.getIdentifier(drawableId, "drawable", context.getPackageName());
let drawable = resources.getDrawable(imgId);
let bitmap = drawable.getBitmap();

这时分的bitmap不能直接运用, 咱们要仿制一下bitmap

bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

扩大心形图片

内置的icon一般都很小, 咱们要把心形扩大到矩形巨细

var img = com.stardust.autojs.core.image.ImageWrapper.ofBitmap(bitmap);
let width = that.width;
let height = that.height;
let fx = 1;
if (width > height) {
  fx = height / img.width;
} else {
  fx = width / img.width;
}
let fy = fx;
let img2 = images.scale(img, fx, fy);

要及时回收图片

events.on("exit", function () {
  img2.recycle();
});
setTimeout(() => {
  img.recycle();
}, 666);

图片搞好以后, 咱们还要给图片设置色彩

图片上色

用扩大后的心形图片, 创立一个canvas实例,

let srcInMode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
// let drawableCanvas = Canvas(iconBitmap);
let drawableCanvas = null;
function tintBitmap(paint, iconBitmap) {
  // change to src in
  paint.xfermode = srcInMode;
  drawableCanvas.drawRect(0, 0, iconBitmap.width, iconBitmap.height, paint);
  paint.xfermode = null;
}

这里用的模式是 SRC_IN , 只显现两者相交的部分, 且显现前景色, 也便是咱们设置的色彩

动画操控

运用的是 ValueAnimator

//  创立动画
function createAnimator(that) {
  //动画
  let animator = ValueAnimator.ofFloat(0, 1);
  animator.setDuration(config.duration);
  animator.setInterpolator(new BounceInterpolator());
  animator.addListener(
    new AnimatorListenerAdapter({
      onAnimationStart: function (animation) {
        that.uiState = UIState.Animating;
      },
      onAnimationEnd: function (animation) {
        that.uiState = that.uiStateStart == UIState.Like ? UIState.UnLike : UIState.Like;
      },
      onAnimationCancel: function (animation) {},
    })
  );
  animator.addUpdateListener(
    new ValueAnimator.AnimatorUpdateListener({
      onAnimationUpdate: function (valueAnimator) {
        let value = valueAnimator.getAnimatedValue();
        that.fraction = value;
        that.view.invalidate();
      },
    })
  );
  return animator;
}

ValueAnimator始终是从0改变到1, 然后赋值给 fraction ,

fraction 改变, 又会引起 scaleX 的改变, scaleX又是 canvas.scale 的参数

canvas.scale(scaleX, scaleY, pivotX, pivotY);

每次制作矩形和心形之前, 都会先缩放canvas

而且修改了默认的差值器, 运用的是 BounceInterpolator , 弹跳插值器, 模仿自由落体后的回弹动画

animator.setInterpolator(new BounceInterpolator());

自定义控件结构

(function () {
  util.extend(CustomView, ui.Widget);
  function CustomView() {
    ui.Widget.call(this);
  }
  CustomView.prototype.render = function () {
    return JavaAdapter(
      android.view.View,
      {
        onDraw: function (canvas) {
          this.super$onDraw(canvas);
          ...
        },
        onMeasure: function (widthMeasureSpec, heightMeasureSpec) {
          this.super$onMeasure(heightMeasureSpec, widthMeasureSpec);
          this.setMeasuredDimension(this.getMeasuredHeight(), this.getMeasuredWidth());
        },
        onSizeChanged: function (w, h, oldW, oldH) {
          this.super$onSizeChanged(w, h, oldW, oldH);
        },
      },
      activity
    );
  };
  CustomView.prototype.onViewCreated = function (view) {};
  CustomView.prototype.onFinishInflation = function (view) {};
  ui.registerWidget("like-button", CustomView);
  return CustomView;
})();

以上, 便是一个点赞动画的要害常识

测试环境

手机: Mi 11 Pro
Android版别: 12
Autojs版别: 9.1.17

名人名言

思路是最重要的, 其他的百度, bing, stackoverflow, github, 安卓文档, autojs文档, 最终才是群里问问 — 牙叔教程

声明

部分内容来自网络 本教程仅用于学习, 禁止用于其他用途\


微信公众号 牙叔教程