携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情 >>
牙叔教程 简单易懂
接着上一篇教程: autojs模仿某东分类导航栏(三)
我们来看看当前导航栏的动画效果
当我们点击 电脑办公 的时候, 电脑办公 会加粗并且字体也变大了, 个护清洁 有一个明显的后移的动作
再看阑槛某东的动画效果
点击母婴童装 后, 后面的男鞋 并没有后移的动作
母婴童装的字体没有明显的放大, 我们使用autojs的布局分析功能, 看看他的宽高变了没有
从图中可以看到, 母婴童装的bounds是
Rect.fromLTRB(345.0, 192.0, 507.0, 267.0)
宽 = 507-345 = 162
高 = 267-192 = 75
这是母婴童装没有加粗的时候的宽高
我们再看看加粗后的宽高
从图中可以看到, 母婴童装的bounds是
Rect.fromLTRB(210.0, 192.0, 384.0, 267.0)
宽 = 384-210 = 174
高 = 267-192 = 75
可以看到宽变大了 174-162 = 12
那么我们再看看加粗之前和之后, 他与其他控件的距离变了没有,
此处说的是 生鲜 和 母婴童装 以及 男鞋 的距离
这个布局分析只能看到控件是紧挨着的, 文字之间的距离未知
\
从布局分析得知, 某东的导航栏不是用的recyclerview, 而是horizontal,
那这个明显后移的动画就这样吧,
我们今天来处理底部的对√动画
在onBindViewHolder中, 添加动画
recyclerview 是通过 数据来改变 view, 我们要添加一个是否绘制动画的属性:animation
如果这个属性为true, 那么我们就绘制动画;
默认都是false, 什么时候这个属性为true呢?
目前是view由非选中状态, 变为选中状态, 且滚动完成以后, 该属性为true.
onBindViewHolder: function (holder, position) {
if (item.animation) {
ui.post(function () {
drawArc(view, view.name, view.arcBg);
});
}
...
我们看看目前的动画
一开始还正常, 之后往右滑动发现多个没有点击过的控件也变成了绿色, 这个就不正常了;
这必然是复用view的问题, 当我们点击了view, 变成了绿色背景,
向左拖动, 绿色背景的view看不见, 就被recyclerview复用了,
看不见的view跑到右侧, 绑定新的数据, 但是绿色背景是没有变的,
因此, 我们在onbind中需要统一修改背景色, 然后选中状态的view, 再修改背景为绿色
这是修改之后的效果, 没有出现复用的问题
\
onBindViewHolder调用次数
我们现在在onbind中只做一个设置文字的操作, 看看滚动rv的时候, onbind会触发几次
onBindViewHolder: function (holder, position) {
log("onBindViewHolder");
// 数据绑定
let view = holder.itemView;
let item = items[position];
log("onBindViewHolder: " + item.name);
view.name.setText(item.name);
左右滑动, 看看日志
每个item只会触发一次onbind
接下来, 我们加上修改背景色, 看看会触发几次
onBindViewHolder: function (holder, position) {
// 数据绑定
let view = holder.itemView;
let item = items[position];
log("onBindViewHolder: " + item.name);
view.name.setText(item.name);
view.arcBg.setBackgroundColor(animationBgColor);
通过日志可以看到也是只触发一次
然后我们在点击事件中, 只增加一个修改背景色的动作, 看看触发次数
view.click(function (view) {
let position = holder.getPosition();
if (items[position].selected) {
return true;
}
currentCategory.selected = false;
currentCategory.animation = false;
recycleAdapter.notifyItemChanged(currentCategory.num);
currentCategory = items[position];
currentCategory.selected = true;
recycleAdapter.notifyItemChanged(currentCategory.num);
onBindViewHolder: function (holder, position) {
// 数据绑定
let view = holder.itemView;
let item = items[position];
log("onBindViewHolder: " + item.name);
view.name.setText(item.name);
view.arcBg.setBackgroundColor(animationBgColor);
if (item.selected) {
view.arcBg.setBackgroundColor(color.parseColor('#00ff00'));
}
日志
脚本加载完成后, 推荐 是默认选中的, 因此显示绿色, 之后我点击了运行, 只进行了一次点击;
日志上有时间, 脚本加载完成是23秒, 点击发生在30秒, 触发了三次onbind,
这个家居生活怎么也触发了? (酒水饮料后面就是家具生活)
我们把view也打印上, 方便看view是否同一个引用
onBindViewHolder: function (holder, position) {
// 数据绑定
let view = holder.itemView;
let item = items[position];
log("onBindViewHolder: " + item.name + ": " + view);
这是脚本加载完的view
08-28 11:58:55.498 main/D: onBindViewHolder: 推荐: android.widget.FrameLayout{acaed76 VFE...C.. ......I. 0,0-0,0}
08-28 11:58:55.503 main/D: onBindViewHolder: 运动: android.widget.FrameLayout{989b7b3 VFE...C.. ......I. 0,0-0,0}
08-28 11:58:55.508 main/D: onBindViewHolder: 电脑办公: android.widget.FrameLayout{b7e341b VFE...C.. ......I. 0,0-0,0}
08-28 11:58:55.514 main/D: onBindViewHolder: 个护清洁: android.widget.FrameLayout{de7ff83 VFE...C.. ......I. 0,0-0,0}
08-28 11:58:55.518 main/D: onBindViewHolder: 酒水饮料: android.widget.FrameLayout{22bb9eb VFE...C.. ......I. 0,0-0,0}
android.widget.FrameLayout{acaed76
前面是view的类型, acaed76 是view的id
现在推荐是选中的, 我们点击一下运动
08-28 12:01:01.867 main/D: 点击的view是:android.widget.FrameLayout{989b7b3 VFE...C.. ...P.... 128,16-208,136}
08-28 12:01:01.886 main/D: onBindViewHolder: 家居生活: android.widget.FrameLayout{439a866 VFE...C.. ......I. 0,0-0,0}
08-28 12:01:01.890 main/D: onBindViewHolder: 推荐: android.widget.FrameLayout{29d2ee VFE...C.. ......I. 0,0-0,0}
08-28 12:01:01.893 main/D: onBindViewHolder: 运动: android.widget.FrameLayout{85bb876 VFE...C.. ......I. 0,0-0,0}
从日志可以看出, 点击的是已经存在的view, 但是在onbind中, 三个view都是新增的view, 因为id和脚本加载完成后的view的id都不一样
点击 电脑办公 试试
08-28 12:05:27.150 main/D: 点击的view是:android.widget.FrameLayout{b7e341b VFE...C.. ...P.... 240,16-400,136}
08-28 12:05:27.166 main/D: onBindViewHolder: 日用百货: android.widget.FrameLayout{acaed76 VFE...C.. .......D 16,16-96,136}
08-28 12:05:27.167 main/D: onBindViewHolder: 运动: android.widget.FrameLayout{989b7b3 VFE...C.. .......D 128,16-208,136}
08-28 12:05:27.170 main/D: onBindViewHolder: 电脑办公: android.widget.FrameLayout{db3642d VFE...C.. ......I. 0,0-0,0}
两个复用, 一个新增
再点运动
08-28 12:07:00.073 main/D: 点击的view是:android.widget.FrameLayout{989b7b3 VFE...C.. ...P.... 128,16-208,136}
08-28 12:07:00.087 main/D: onBindViewHolder: 运动: android.widget.FrameLayout{85bb876 VFE...C.. .......D 128,16-208,136}
08-28 12:07:00.088 main/D: onBindViewHolder: 电脑办公: android.widget.FrameLayout{b7e341b VFE...C.. .......D 240,16-400,136}
再点推荐
08-28 12:07:32.791 main/D: 点击的view是:android.widget.FrameLayout{29d2ee VFE...C.. ...P.... 16,16-96,136}
08-28 12:07:32.798 main/D: onBindViewHolder: 推荐: android.widget.FrameLayout{989b7b3 VFE...C.. .......D 128,16-208,136}
08-28 12:07:32.799 main/D: onBindViewHolder: 运动: android.widget.FrameLayout{db3642d VFE...C.. .......D 240,16-400,136}
点击运动和推荐, 他们的view都是复用已存在的控件
为什么点击运动的时候, 他要新增三个view呢?
notifyItemChanged 不是非必要只触发onbindviewholder吗?
rv又没有滚动, 干嘛要新增view, 直接绑定数据不就行了, 为啥还有新增?
在这里有个类似的问题
stackoverflow.com/questions/3…
RecyclerView使用这两个ViewHolder来平滑从旧状态到新状态的动画。这是RecyclerView.ItemAnimator的默认行为。
您可以通过将空项目动画器传递给RecyclerView来禁用动画:
listView.setItemAnimator(null);
我把itemanimator设置为null, 这样就符合我的预期了, 不会新建我觉得多余的view
开始画对√的动画
我们来看看目前的动画
看着符合预期, 但是当滚动的时候, 可以看到酒水饮料闪了一下, 这个不符合预期,
我的鼠标是在日用百货上面开始按下去再拖动鼠标, 酒水饮料那里不应该触发动画,
因为酒水饮料已经触发过动画, 且现在他就是选中状态, 所以不应该多次触发动画;
\
修正以后的动画, 基本差不多了
但是还有个bug, 我们选中个护清洁, 然后向左拖动, 再向右拖动, 个护清洁下面的对勾就不见了
\
这个是由于复用的view的宽高不一样, 而背景却使用同一只画笔来绘制, 画笔设置 setShader ,
shader又是一个LinearGradient的线性渐变, 两个字右侧基本是透明色看不见, 而个护清洁是四个字,
起点基本就是透明色, 因此看不见, 实际上是绘制了
动画完成之后, 把shader缓存一下, 就可以解决这个问题
环境
雷电模拟器:9.0.17
Android版本: 9
Autojs版本: 9.2.8
名人名言
思路是最重要的, 其他的百度, bing, stackoverflow, github, 安卓文档, autojs文档, 最后才是群里问问 --- 牙叔教程
声明
部分内容来自网络 本教程仅用于学习, 禁止用于其他用途\