autojs点赞按钮动画

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

牙叔教程 简单易懂

正常动画速度500ms

慢速动画3秒

思路

  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文档, 最后才是群里问问 --- 牙叔教程

声明

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


微信公众号 牙叔教程

猜你喜欢

转载自juejin.im/post/7101935627771478024