autojs自己写布局分析

984 阅读3分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第9篇文章,点击查看活动详情

牙叔教程 简单易懂

要达到的效果

autojs自带的布局分析是这样的

\

绿框里面是控件的节点信息, 我们要展示绿框, 首先要提取当前界面的节点信息;

根节点

let windowRoot = auto.rootInActiveWindow;
log(windowRoot);
UiObject(id=null, sourceNodeId=-2147483650, packageName=org.autojs.autojspro, className=android.widget.FrameLayout, text=null, desc=null, indexInParent=-1, boundsInParent=[0,0][1080,1920], boundsInScreen=[0,0][1080,1920], checkable=false, checked=false, focusable=false, focused=false, selected=false, clickable=false, longClickable=false, enabled=true, password=false, scrollable=false)

\

屏幕上绘制多少个绿框

如果节点有几十几个百个, 问题不大, 如果有几千个呢?

节点太多, 会影响绘制绿框的速度;

因此, 我们要限制绿框的数量.

假设节点有上千个, 我们绘制那些绿框呢?

\

图中一共有6个节点, 如果我们只绘制3个节点,

那么我们绘制谁呢?

用户需要使用什么, 我们就绘制什么.

一般我们选择节点都不会是顶端的节点, 而是偏向底层的节点,

因此, 我们应该绘制DEF这三个节点.

如何获得DEF三个节点信息

必然要从根节点开始遍历

怎么遍历节点

遍历节点有2种方式: 深度(Depth First)和广度(Breadth First),

我们要获取的节点是DEF, 这三个节点是同一层的节点, 应当用 广度( Breadth First ) ;

BF遍历代码

  1. 获取当前界面根节点
let windowRoot = auto.rootInActiveWindow;
  1. 变量 viewNodes 存储节点
let viewNodes = [];
viewNodes.push(windowRoot);
  1. 存储根节点的直接子节点
let viewNodes = [];
viewNodes.push(windowRoot);
var childCount = windowRoot.childCount();
for (var i = 0; i < childCount; i++) {
    let childViewNode = windowRoot.child(i);
    viewNodes.push(childViewNode);
}
  1. 第二层我们访问完了, 接着该访问第三层了, 按照第二层子节点的顺序, 一次访问第三层;
var childCount = secondLevelViewNodeA.childCount();
for (var i = 0; i < childCount; i++) {
    let childViewNode = secondLevelViewNodeA.child(i);
    viewNodes.push(childViewNode);
}

以此类推

  1. 第三层访问完了, 接着访问第四层
var childCount = thirdLevelViewNodeA.childCount();
for (var i = 0; i < childCount; i++) {
    let childViewNode = thirdLevelViewNodeA.child(i);
    viewNodes.push(childViewNode);
}

\

  1. 节点的层数是不确定的, 我们也不清楚当前还有哪些节点需要遍历, 因此, 我们要一个队列, 来存储需要遍历的节点, 显而易见的, 我们要写一个 广度( Breadth First ) 递归
function findViewNodes(viewNode) {
    let viewNodes = [];
    let breadthViewNodes = [];
    // 节点加入队列
    breadthViewNodes.push(viewNode);
    // 遍历队列中的节点
    while (breadthViewNodes.length > 0) {
        let headViewNode = breadthViewNodes.shift();
        // 子节点入队列
        let childCount = headViewNode.childCount();
        for (let i = 0; i < childCount; i++) {
            let childViewNode = headViewNode.child(i);
            breadthViewNodes.push(childViewNode);
        }
        // 父节点入库
        viewNodes.push(headViewNode);
    }
    return viewNodes;
}

这一段代码也许有的人不太好理解, 大家可以想象一下, 机关枪;

子弹发射之后, 一颗子弹 有概率 变成两颗, 三颗, 然后重新回到弹夹中,

弹夹空了以后, 我们就获得了所有不会再分裂的子弹.

并且, 这些子弹都是按分裂的次数, 就和游戏里宝宝变异的不同级别一样,

每层都是同等级变异的宝宝, 这体现了数据的顺序性.

\

限制绘制的绿框数量

我们可以把限制的数量, 放到一个配置中, 方便后期修改;

这里我们指定限制绘制10个绿框;

上面解析了所有的节点, 存到了一个数组中,

用户常用的是节点面积区域最小的节点, 因此我们从后往前截取10个节点;

let viewNodes = findViewNodes(windowRoot);
let childViewNodes = viewNodes.slice(-10)

绘制绿框

我们要的节点数据有了, 主要是节点的bounds数据;

下面开始绘制, 绘制的话, 先创建一个全屏悬浮窗, 然后多次绘制矩形

let paint = new Paint();
paint.setColor(colors.parseColor("#00ff00"));
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
window.canvas.on("draw", function (canvas) {
    var len = childViewNodes.length;
    for (var i = 0; i < len; i++) {
        let childViewNode = childViewNodes[i];
        let bounds = childViewNode.bounds();
        let left = bounds.left;
        let top = bounds.top;
        let right = bounds.right;
        let bottom = bounds.bottom;
        canvas.drawRect(left, top, right, bottom, paint);
    }
});

\

到这里本篇教程的目的: 绘制绿框, 就达到了;

之后有时间了, 会继续模仿autojs的布局分析

环境

设备: 小米11pro
Android版本: 12
雷电模拟器:9.0.17
Android版本: 9
Autojs版本: 9.2.13

名人名言

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

声明

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

微信公众号 牙叔教程