问题背景

在一些情况下,即使获取了所需的控件,控件的clickable属性也可能为false,这时就无法直接通过click()点击控件,转而需要通过其坐标来模拟点击动作

另一种情况是,目标控件的text为"确认",但发现页面上有多个"确认",此时也可以基于坐标来限定控件的范围,从而筛选出唯一的所需的控件

  • 不要滥用基于坐标定位的方法
    尽管用定位控件的方法对于静态页面十分准确,却无法兼容不同分辨率的设备;同时对于列表页面等动态页面无法达到效果,因此尽量不要使用基于坐标的脚本,以提高通用性
  • 要获取要点击的位置的坐标,可以在开发者选项中开启"指针位置"
  • 使用控件的bounds属性可获取控件坐标

控件的bounds属性

在Auto.js软件提供的布局范围分析中,可以获取一个控件的坐标范围
控件属性bounds(left, top, right, buttom)

  • left {number} 控件左边缘与屏幕左边的距离
  • top {number} 控件上边缘与屏幕上边的距离
  • right {number} 控件右边缘与屏幕左边的距离
  • bottom {number} 控件下边缘与屏幕上边的距离

例如某控件的bounds属性为(951, 67, 1080, 196)

注意,bounds属性中的最大数值与手机尺寸有关
可以使用device.width来获取屏幕宽度,device.height来获取屏幕高度

与bounds相关的方法

UiSelector.bounds(left, top, right, bottom)

可以用bounds这个范围来定位这个控件。尽管用这个方法定位控件对于静态页面十分准确,却无法兼容不同分辨率的设备;同时对于列表页面等动态页面无法达到效果,因此使用不推荐该选择器。

例如,若某控件的bounds属性为(951, 67, 1080, 196),此时使用代码bounds(951, 67, 1080, 196).click()即可点击该控件。

UiSelector.boundsInside(left, top, right, buttom)

用于限定控件:只在在某一个区域内选择控件
例如,在屏幕上半部分选择一个"确定"控件,并点击

var w = text("确定").boundsInside(0, 0, 
		device.width,device.height/2).findOne();
w.click();
UiSelector.boundsContains(left, top, right, buttom)

用于限定控件:选择出的控件必须包含“left, top, right, buttom”构成的范围
例如,已知某个特定坐标,要寻找在这个点上的可点击控件,可使用此方法

UiObject.bounds()

返回一个控件的bounds属性,其值是一个Rect对象,表示一个长方形(范围)
有Rect.left、Rect.right、Rect.top、Rect.bottom、Rect.centerX()、Rect.centerY()、Rect.width()、Rect.height()、Rect.contains(rect2)、Rect.intersect(rect2)等属性和方法,详见官方文档

应用:基于坐标的模拟触摸

如果一个控件本身无法通过click()点击,那么我们可以利用bounds()函数获取其坐标,再利用坐标点击。

var widget = id("xxx").findOne();
//获取控件
click(widget.bounds().centerX(), widget.bounds().centerY());
//获取其中心位置并点击
//如果用root权限则用Tap

由此可以得到一些一般化处理的函数

//传入控件,用其坐标模拟点击
function clickBtn_Coord(btn) {
    if (!btn) return false;
    var coord = btn.bounds();
    while (!click(coord.centerX(), coord.centerY()));//确保点击成功
    return true;
}

//以text查找控件并用坐标模拟点击
function clickByText_Coord(btnText, waitingDelay) {
    var btn = text(btnText).findOne(waitingDelay);
    if (!btn) return false;
    var coord = btn.bounds();
    while (!click(coord.centerX(), coord.centerY()));
    return true;
}

基于坐标的脚本在不同设备上的分辨率问题

尽管用定位控件的方法对于静态页面十分准确,却无法兼容不同分辨率的设备

对于基于坐标的脚本遇到的分辨率问题,可通过setScreenMetrics()函数进行自动坐标放缩。这个函数会影响所有点击、长按、滑动等函数。通过设定脚本设计时的分辨率,使得脚本在其他分辨率下自动放缩坐标

setScreenMetrics(width, height)
  • 设置脚本坐标点击所适合的屏幕宽高
  • 如果脚本运行时,屏幕尺寸不一致会自动放缩坐标

例如在1920*1080的设备中,基于坐标的点击操作为

setScreenMetrics(1080, 1920);
click(800, 200);

Auto.Js会自动在不同设备上放缩坐标,以便脚本仍然有效
如在540 * 960的屏幕中,click(800, 200)实际上会点击位置(400, 100)。

更多基于坐标的操作

以下的x,y表示坐标值

  • click(x, y)模拟点击,并返回是否成功,时长约150ms
    模拟连续点击时可能有连击速度过慢的问题,可以用press()函数代替
  • longClick(x, y)模拟长按,时长约600ms
  • press(x, y, duration)模拟按住,duration为按住时长(单位ms)
    按住时长较短,被系统认为是点击;时长超过500毫秒,则被系统认为是长按
  • swipe(x1, y1, x2, y2, duration)模拟从坐标(x1, y1)滑动到坐标(x2, y2),返回是否成功
  • gesture(duration, [x1, y1], [x2, y2], ...)模拟沿着一系列路径滑动
    gesture(1000, [0, 0], [500, 500], [500, 1000])
  • gestures([delay1, duration1, [x1, y1], [x2, y2], ...], [delay2, duration2, [x3, y3], [x4, y4], ...], ...)模拟多个同时的手势。每个手势的参数为[delay, duration, 坐标], delay为延迟多久(毫秒)才执行该手势(可省略,默认为0);duration为执行时长;
    例如手指捏合:
gestures([0, 500, [800, 300], [500, 1000]],
         [0, 500, [300, 1500], [500, 1000]]);
  • 一些其他的点击和滑动命令需要Root权限,如RootAutomator.tap(x, y[, id])RootAutomator.touchDown(x, y[, id])等,详见官方文档
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐