autojs模仿某东分类导航栏(二)

牙叔教程 简单易懂


接着上一篇教程

autojs模仿某东分类导航栏

https://www.yuque.com/yashujs/bfug6u/novbne


上一篇教程写了导航栏的基础部分, 这篇教程我们添加导航栏的动画


某东的导航栏效果


他这个动画是在文字下方画一段圆弧, 是有画这个过程的, 大概300ms;


怎么画圆弧

canvas画圆弧的方式是

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧,


我们先单独测试画圆弧

ui.layout(
    
        
    
);

真个界面就只有一个canvas


设置canvas的canvas事件

let startAngle = 135;
let sweepAngle = -100;
let useCenter = false;
ui.board.on("draw", function (canvas) {
    canvas.drawColor(colors.BLACK);
    canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint); //画弧,
});

画出来的圆弧是这样的


怎么让他300ms慢慢画完呢?

通过修改背景的方式让他慢慢画完


我们搞一个示例看看

就给只有一个View

ui.layout(
    
        
    
);


给View设置背景

var drawable = new android.graphics.drawable.Drawable({
    draw: function (canvas) {
        canvas["drawColor(int)"](colors.BLACK);
        canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint); //画弧,
    },
});
ui.board.setBackgroundDrawable(drawable);


其中的sweepAngle, 我们用 ValueAnimator 来控制

animator.addUpdateListener(
    new ValueAnimator.AnimatorUpdateListener({
        onAnimationUpdate: function (animation) {
            let value = animation.getAnimatedValue();
            sweepAngle = -value;
            ...
        },
    })
);


慢慢画弧 演示效果


给导航栏添加背景动画

let itemLayout = (
    
        
        
    
);

然后在点击事件中, 添加动画, 这时又遇到一个问题,


什么时候开始执行动画?

这里我们设计为在滚动结束之后, 开始执行动画;

新的问题又来了, 我们怎么知道滚动结束了?


我们给rv添加一个滚动监听

rv滚动有三种状态

//停止滚动
public static final int SCROLL_STATE_IDLE = 0;
 
//正在被外部拖拽,一般为用户正在用手指滚动
public static final int SCROLL_STATE_DRAGGING = 1;
 
//自动滚动开始
public static final int SCROLL_STATE_SETTLING = 2;

我们只需要在监听 停止滚动 的时候, 开始画圆弧


画圆弧之前要知道的数据

  • 圆弧的起点
  • 圆弧的终点
  • 圆弧的半径


圆弧的起点是哪里?

再次查看某东的动画, 可知, 圆弧在文字中间正下方, 左右各一半圆弧;



那么

圆弧的起点横坐标 = 文字控件中心横坐标 - 一个字的宽度*0.75

圆弧的起点纵坐标 = 文字底部纵坐标


在按照这个公式计算的时候, 发现一个问题: 作为背景的view宽度是0!

作为动画的背景xml是这样的

整个itemXml是这样的

let itemLayout = (
    
        
        
    
);


动画背景宽度是0的话, 我们这个计算就没用了, 宽度为0的画板, 画啥也看不见;


因此, 我们得改改这个itemLayout, 修改之后的itemLayout, 动画背景的宽高以textView为标准

let itemLayout = (
    
        
        
    
);

动画背景的宽度arcBg要在recyclerview的onBindViewHolder方法中动态设置

onBindViewHolder: function (holder, position) {
    ...
    let textViewWidth = getViewWidth(view.name);
    view.arcBg.attr("w", textViewWidth + "px");
}


动画背景的宽度解决以后, 我们就可以套用上面的公式了,

画圆弧的效果如下:


这个圆弧是瞬间绘制的, 不是慢慢画出来的, 我们要加一个 ValueAnimator 来控制这个圆弧 sweepAngle 的数值在一定时间内慢慢变大


我们来看看 这个监听器怎么写的

let updateListener = new ValueAnimator.AnimatorUpdateListener({
    onAnimationUpdate: function (animation) {
        let value = animation.getAnimatedValue();
        sweepAngle = -value;
        var drawable = new android.graphics.drawable.Drawable({
            draw: function (canvas) {
                canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint); //画弧,
            },
        });
        ui.board.setBackgroundDrawable(drawable);
    },
});
animator.addUpdateListener(updateListener);

监听器的方法都是类似了, 只有几个参数需要发生变化, 我们有两种写监听器的思路

  • 动画开始绘制的时候, 先移除旧的监听器, 再添加新的监听器, 这样要多次写监听器
  • 动画开始绘制的时候, 改变监听器里的, 必须修改的变量的值, 这样只写一次监听器即可


我选择第二种, 那么我们来看看监听器里面有哪些参数需要外部修改

  • ui.board 要把这个改成动画的view


其他参数都不需要外部修改, 因为某东导航栏的动画都是一模一样的, 圆弧的起点, 终点, 高度, 都没有任何变化


我们就定义一个变量, 来引用当前的动画view

let currentArcView=null;


2s慢动画效果


颜色应该加一个渐渐透明, 那么我们就再加一个 ValueAnimator, 用来管理透明度

let animator = new AnimatorSet();
let animatorSweepAngle = ValueAnimator.ofInt(0, 100);
let animatorAlpha = ValueAnimator.ofInt(0, 255);
animator.playTogether([animatorSweepAngle, animatorAlpha]);


但是问题来了, 慢慢画的效果出来了, 最后透明全都看不见了

因此, 我们这种修改背景, 模拟动画的方式需要改改

var drawable = new android.graphics.drawable.Drawable({
    draw: function (canvas) {
        paint.setColor(colors.argb(currentAlpha, red, green, blue));
        canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint); //画弧,
    },
});
currentArcView.setBackgroundDrawable(drawable);


怎么改呢?

我们给画笔设置shader, 我们做一个 LinearGradient, 搞成渐变色那种, 从左往右, 渐渐透明

public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[], @Nullable float positions[], @NonNull TileMode tile) 
let linearGradient = new LinearGradient(0, 150, 300, 150, colorArr, positions, Shader.TileMode.CLAMP);
let paint = new Paint();
paint.setShader(linearGradient);
ui.board.on("draw", function (canvas) {
    canvas.drawColor(colors.BLACK);
    canvas.drawRect(0, 0, 300, 300, paint);
});

渐渐透明的紫色


接下来, 我们就用shader的方式来解决动画问题, 透明度的修改就没必要了, 因为透明度已经被包含在shader里面了

// animator.playTogether([animatorSweepAngle, animatorAlpha]);
animator.playTogether([animatorSweepAngle]);


渐变的动画效果


新的问题又出现了, 我点击的是 酒水饮料, 可他还是在 个护清洁 上面做动画

这个明显是因为没有及时更新点击的控件, 我们更新即可


新的问题又来了, 点击那个控件, 那个控件就做动画, 上一个控件没有清理动画

那么, 我们需要给数据添加一个状态属性, 勾选或者没有勾选


上面是在模拟器测试的, 我们去手机上看看效果


手机上字都显示不全


除了这个问题, 还有一些别的问题, 下次再解决


环境

手机:小米11pro
MIUI: 13.0.12
Android版本: 12
Autojs版本: 9.2.6


名人名言

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

声明

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

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章