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

188 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情 >>

牙叔教程 简单易懂

接着上一篇教程: autojs模仿某东分类导航栏

www.yuque.com/yashujs/bfu…

某东不同分辨率效果

上一篇最后我们在模拟器上调试的代码, 在手机上文字显示不全,

我们来看看某东在不同分辨率下的显示情况

540X960

\

720X1280

\

900X1600

\

1080X1920

\

基本一致

我们再看看之前自己写的导航栏

1080X1920

540X960

\

完全不一样, 剩下的分辨率就不用看了

我们今天就来处理这个分辨率导致布局不一样的问题

分析宽高

一行5个类目, 字数 12 + 6, 一行大概18个字符的宽度, 不考虑右侧的分类;

我们要在一行放置18个字, 且每个分辨率都是18个字,

首先我们第一个基准分辨率, 模拟器当前设定的是 720X1280,

基本思路是: 以基准分辨率为准, 布局设计好以后, 其他分辨率换算为具体的像素值, 以便进行多分辨率布局适应.

这是18个字的效果

ui.layout(
    <vertical>
        <text id="content" textSize='20dp' bg='#cccccc' ></text>
    </vertical>
);

ui.content.setText("牙叔".repeat(8)+'末尾');

文字单位选用的20dp

我们看看别的分辨率显示的效果怎么样

三种分辨率文字效果是一模一样的

\

为了使文字宽高在不同分辨率效果一样, 我们以后就使用dp来作为文字单位

添加文字的textSize属性

之前导航栏的子布局是

let itemLayout = (
    <frame w="wrap_content" margin="8" h="60dp">
        <View id="arcBg" h="match_parent" />
        <text id="name" layout_gravity="center" w="wrap_content" h="wrap_content" margin="0" padding="0" textColor="#5e128a" gravity="center"></text>
    </frame>
);

文字是没有设置textSize的, 我们加上去, textSize="20dp"

\

效果还是不一样

为什么设置了dp, 效果还是不一样

之前在onbindviewholder中, 我们会动态设置textsize大小, 我们先注释掉, 看看效果

\

这下文字大小就完全一致了

那么我们设置同样的字体大小, 效果又如何?

照理说应该一样才对, 现在是完全禁忌不一样, 我们用安卓的方法, 修改字体大小试试

原来修改字体大小是

view.name.attr("textSize", "20dp");

我们改为

view.name.setTextSize(android.util.TypedValue.COMPLEX_UNIT_DIP, 20);

\

aj修改字体大小有bug, 我们用安卓原生的setTextSize就没问题

文字宽度和动画的顺序问题

onBindViewHolder是RecyclerView数据更新的统一处理位置, 我们在这里会改变文字的大小;

我们来测试一下四个时刻的文字view的宽度

  • setTextSize之前
  • setTextSize之后
  • ui.post
  • ui.post 一秒后

我们只测试选中状态的文字宽度

动画是在点击之后, 也就是文字view已经可以看见了, 但是可能还不是选中状态, 而且可能发生滚动,

所以我们还要看一下点击的时候宽度的变化

  • 点击之后
  • 点击之后开始滚动, 滚动结束后

这说明只要view可见一部分, 那么就和整体可见, 宽度是一致的

宽高确定了, 那么就可以开始测试动画了, 动画是在滚动完成之后来绘制的

动画绘制

现在的问题是动画没反应

代码是这样的

animatorSweepAngle.addUpdateListener(
    new ValueAnimator.AnimatorUpdateListener({
        onAnimationUpdate: function (animation) {
            let value = animation.getAnimatedValue();
            sweepAngle = -value;
            var drawable = new android.graphics.drawable.Drawable({
                draw: function (canvas) {
                    canvas.drawColor(Color.GREEN);
                },
            });
            log("currentArcView = " + currentArcView);
            currentArcView.setBackgroundDrawable(drawable);
        },
    })
);
currentArcView = android.view.View{d2591f8 V.ED..... ......ID 0,0-160,120 #2} 

view的宽高是有的, canvas调用drawColor绘制颜色也没问题, 但view背景就是没变成绿色, 好奇怪呀?

我们先不用animator, 先单独测试设置背景

"ui";
ui.layout(
    <vertical>
        <View id="test" w="100dp" h="100dp"></View>
    </vertical>
);
let currentArcView = ui.test;
var drawable = new android.graphics.drawable.Drawable({
    draw: function (canvas) {
        canvas.drawColor(android.graphics.Color.GREEN);
    },
});
currentArcView.setBackgroundDrawable(drawable);

单独测试是可以的;

上面这个是模拟器的效果, 我们在手机上也测试一下

手机上显示的是白色

我们把canvas绘制颜色的方法限制一下参数类型

canvas.drawColor(android.graphics.Color.GREEN);

改成

canvas["drawColor(int)"](android.graphics.Color.GREEN);

改完以后, 在手机上和模拟上就都是绿色了

我们多加点日志

onBindViewHolder: function (holder, position) {
    log("onBindViewHolder");

我每点击一次文字控件, 就会打印一次 onBindViewHolder;

那么onbind和动画孰先孰后呢?

我们继续添加日志

  'onBindViewHolder: 进入',
  'onBindViewHolder: setText',
  'drawArc: 进入',
  'drawArc: setText' ] 

先 onbind 后 drawarc, 顺序和预期一样,

如果修改背景不行的话, 我们试试修改文字

view2.setText('aaaaaaaa')

点击以后文字确实修改了, 可是又很快变回原来的 推荐. 这是为什么呢?

这里就有一个知识点, 你觉得你能单独控制recyclerview里的view吗?

从实际情况来看, 并不能, 就能勉强能, 也有各种各样的bug,

所以, 我们把动画迁移到 onBindViewHolder 中.

可以看到, 用同样的方法修改背景色, 是没问题的

什么时候触发动画?

  1. 从未选中状态变成了选中状态
  2. 滚动完成以后
  3. 通知recyclerview控件可以开始动画了

先来看第一条, 从未选中状态变成了选中状态:

如果本来就是选中的, 那么我们什么都不需要做;

如果不是选中的, 那么开始判断有没有滚动完成;

这个选中状态的判断是在 onCreateViewHolder 中的控件点击事件中处理的;

view.click(function (view) {
    let position = holder.getPosition();
    if (items[position].selected) {
        return true;
    }
...

再看第二条: 滚动完成以后

这个肯定是在监听里面才能知道, 我们添加的监听是

rv.addOnScrollListener(
    new Packages.androidx.recyclerview.widget.RecyclerView.OnScrollListener({
        onScrollStateChanged: function (recyclerView, newState) {
            if (newState == 0) {
                 // 滚动完成
...

\

最后是第三条, 在滚动完成后, 通知recyclerview更新

if (newState == 0) {
    recycleAdapter.notifyItemChanged(currentCategory.num);
}

通知更新以后, 触发onBindViewHolder

接下来开始迁移真正的动画部分, 下次再说

环境

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

名人名言

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

声明

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

微信公众号 牙叔教程