autojs点赞按钮动画

简介: 牙叔教程 简单易懂

牙叔教程 简单易懂


正常动画速度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文档, 最后才是群里问问 --- 牙叔教程

声明

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

相关文章
|
JavaScript Windows Python
Windows DOS进入指定盘符(磁盘路径)
Windows DOS进入指定盘符(磁盘路径)
514 1
|
Android开发
autojs下拉刷新
牙叔教程 简单易懂
1141 0
|
人工智能 前端开发 Java
autojs非常见函数1
牙叔教程 简单易懂
2367 0
|
Android开发
autojs无Root访问data目录实现
牙叔教程 简单易懂
2839 0
|
测试技术 Android开发
autojs横屏截图的正确姿势
牙叔教程 简单易懂
3308 0
|
12月前
|
存储 安全 数据库
后端技术在现代Web开发中的实践与创新
【10月更文挑战第13天】 本文将深入探讨后端技术在现代Web开发中的重要性,通过实际案例分析展示如何利用先进的后端技术提升用户体验和系统性能。我们将从基础架构设计、数据库优化、安全性保障等方面展开讨论,为读者提供清晰的指导和实用的技巧。无论是新手开发者还是经验丰富的技术人员,都能从中获得启发和帮助。
241 2
|
新制造 SDN 网络虚拟化
SD-WAN 大战 MPLS VPN 多年,赢了吗?
在过去的10年中,SDN(软件定义网络)已在数据中心和云节点之间的网络中得到广泛应用。而SD-WAN(软件定义广域网)则解决了各种复杂的广域网连接场景,成为大多数中小型企业组网的首选方案。 尽管当前SD-WAN市场有着广泛的应用,但在经过近几年的发展后,我们也开始意识到SD-WAN面临着各种问题,其中有些问题是不可调和的。那么,SD-WAN的发展面临哪些阻碍?如何应对这些挑战?本文将着重探讨这些问题,同时分享行业的最佳实践。
SD-WAN 大战 MPLS VPN 多年,赢了吗?
|
存储 安全 数据库
对称加密的日常实践应用:以AES为例的加密解密指南
**摘要:** 本文介绍了对称加密算法AES在数据安全中的应用,强调了其在文件、通信和数据库加密中的重要性。通过Python示例展示了如何使用`cryptography`库实现AES-256的加密和解密,涉及密钥生成、CBC模式及PKCS7填充。同时,提醒注意密钥管理、模式选择和填充方式的选择对加密安全性的影响。
1463 1
|
Android开发
autojs-dialog对话框倒计时
牙叔教程 简单易懂
1164 1