Skip to content

选择器 UiSelector ​

UiSelector 按节点属性筛选当前界面,再交给 UiObject 点击、输入或滑动。Android 界面由节点组成:文字是 TextView,图片是 ImageView,位置由布局决定。节点常见属性有 text、desc、className、id、clickable。

有节点时用选择器。没有稳定文本或节点树拿不到时,再用坐标,见 手势 Gesture。写脚本前可先用 节点查看器 看属性。

不带参数或 UiSelector(true) 是简单模式。UiSelector(false) 是复杂模式,能看到更多节点(含状态栏等系统节点)。

javascript
let sendButton = UiSelector().text('发送').findOne();
if (sendButton) {
    sendButton.click();
}

条件可以链式叠加,后接 findOne / find 才真正去查。

条件 ​

方法作用
id(name)id 等于 name(对应 viewIdResourceName)
className(name)类名等于 name
bounds(left, top, right, bottom)节点矩形范围
text(content)文本等于 content
desc(content)描述等于 content(对应 contentDescription)
clickable(canClick)是否可点击
selected(isSelected)是否已选择
checked(isChecked)是否勾选
enabled(isEnabled)是否可用
focusable(canFocus)是否可获焦
focused(isFocused)是否已获焦
editable(canEdit)是否可编辑
scrollable(canScroll)是否可滚动
isVisibleToUser(visible)是否对用户可见
textContains(content)文本包含 content
textMatches(content)文本正则匹配
descContains(content)描述包含 content
descMatches(content)描述正则匹配
filter(callback)按回调再过滤

查找 ​

方法作用
exists()当前条件能否匹配到节点
waitFindOne()一直等到节点出现
find()所有匹配节点
findBy(uiSelector)在已匹配节点的子树里再查
findBy(timeout)最多等 timeout 毫秒再 find
findOne()第一个匹配节点
findOnce()同 findOne
findOne(uiSelector)在已匹配节点的子树里找第一个
findOneBy(uiSelector)子树里找到一个立刻返回
findOneBy(timeout)最多等 timeout 毫秒找一个

id(name) ​

参数:

  • name {string} 节点 id

返回: {UiSelector} 选择器自身,可继续链式调用

对应节点选择器里的 viewIdResourceName。

className(name) ​

参数:

  • name {string} 类名,如 "TextView"、"EditText"

返回: {UiSelector} 选择器自身

bounds(left, top, right, bottom) ​

参数:

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

返回: {UiSelector} 选择器自身

按节点在屏幕上的矩形筛选。

text(content) ​

参数:

  • content {string} 完整文本

返回: {UiSelector} 选择器自身

文本必须整段相等。要模糊匹配用 textContains 或 textMatches。

desc(content) ​

参数:

  • content {string} 完整描述

返回: {UiSelector} 选择器自身

对应 contentDescription。图标按钮常常只有描述、没有文本。

clickable(canClick) ​

参数:

  • canClick {boolean} 是否可点击

返回: {UiSelector} 选择器自身

selected(isSelected) ​

参数:

  • isSelected {boolean} 是否已选择

返回: {UiSelector} 选择器自身

checked(isChecked) ​

参数:

  • isChecked {boolean} 是否勾选

返回: {UiSelector} 选择器自身

enabled(isEnabled) ​

参数:

  • isEnabled {boolean} false 表示禁用

返回: {UiSelector} 选择器自身

focusable(canFocus) ​

参数:

  • canFocus {boolean} 是否可以获取焦点

返回: {UiSelector} 选择器自身

focused(isFocused) ​

参数:

  • isFocused {boolean} 是否已经获取焦点

返回: {UiSelector} 选择器自身

editable(canEdit) ​

参数:

  • canEdit {boolean} 是否可编辑

返回: {UiSelector} 选择器自身

scrollable(canScroll) ​

参数:

  • canScroll {boolean} 是否可滚动

返回: {UiSelector} 选择器自身

isVisibleToUser(isVisibleToUser) ​

参数:

  • isVisibleToUser {boolean} 是否对用户可见

返回: {UiSelector} 选择器自身

javascript
let visibleButton = UiSelector().isVisibleToUser(true).text('发送').findOne();

textContains(content) ​

参数:

  • content {string} 子串

返回: {UiSelector} 选择器自身

可以连续调用,要求同时包含多段文字。

javascript
let tag = UiSelector().textContains('点赞').textContains('按钮').findOne();

textMatches(content) ​

参数:

  • content {string|RegExp} 正则或普通字符串

返回: {UiSelector} 选择器自身

传入普通字符串时,效果和 textContains 一样。

javascript
let tag = UiSelector().textMatches(/点赞/).findOne();
let tag2 = UiSelector().textMatches(/\d+/).findOne();
let tag3 = UiSelector().textMatches('点赞').findOne();

descContains(content) ​

参数:

  • content {string} 子串

返回: {UiSelector} 选择器自身

javascript
let tag = UiSelector().descContains('点赞').descContains('按钮').findOne();

descMatches(content) ​

参数:

  • content {string|RegExp} 正则或普通字符串

返回: {UiSelector} 选择器自身

传入普通字符串时,效果和 descContains 一样。

javascript
let tag = UiSelector().descMatches(/点赞/).findOne();
let tag2 = UiSelector().descMatches(/\d+/).findOne();
let tag3 = UiSelector().descMatches('点赞').findOne();

filter(callback) ​

参数:

  • callback {function} 入参是 UiObject;返回 true 保留,返回 false 丢掉该节点

返回: {UiSelector} 选择器自身,可继续链式调用(再接 findOne / find / exists 等)

在其它条件匹配到的节点上,再按自定义逻辑筛一遍。点击前一般先用 filter 丢掉屏幕外节点(很少需要操作屏外内容)。常见用途:

场景为什么要用 filter
过滤屏幕外的节点(默认)同 id / 同文本常有多份;findOne() 可能先拿到屏幕外的(bounds.top < 0 等),一点击就会点偏
限制在某一侧操作栏只要右侧点赞/评论按钮:bounds().left > Device.width() * 0.7
排除过小 / 过大的热区避免点到整块大容器误进个人主页
组合属性判断例如只要可点击且中心点在屏幕可见区域内

isVisibleToUser(true) 不能代替屏内几何校验:部分机型 / 场景下,屏幕外节点仍可能被标成可见。生成点击代码时,默认用 filter 再确认坐标。

过滤屏幕内节点(推荐):

javascript
let likeBtn = UiSelector()
    .id('com.ss.android.ugc.aweme:id/gpf')
    .filter(function (node) {
        if (!node) {
            return false;
        }
        let b = node.bounds();
        if (!b || b.width() <= 0 || b.height() <= 0) {
            return false;
        }
        // 丢掉屏幕外或越界节点
        if (b.left < 0 || b.top < 0) {
            return false;
        }
        if (b.right > Device.width() || b.bottom > Device.height()) {
            return false;
        }
        return true;
    })
    .findOne();
if (likeBtn) {
    likeBtn.click();
}

按区域过滤(例如只要右侧操作栏):

javascript
let commentBtn = UiSelector()
    .id('com.ss.android.ugc.aweme:id/e0d')
    .filter(function (node) {
        let b = node.bounds();
        return b && b.left >= 0 && b.top >= 0 && b.left > Device.width() * 0.7;
    })
    .findOne();

简单坐标条件:

javascript
let ui = UiSelector().filter(function (v) {
    return v && v.bounds() && v.bounds().left > 100 && v.bounds().top > 300;
}).findOne();

也可用箭头:UiSelector().filter((v) => v && v.bounds() && v.bounds().left > 100).findOne()。

exists() ​

返回: {boolean} 能匹配到至少一个节点时为 true

只判断在不在,不返回节点。

javascript
if (UiSelector().text('发送').exists()) {
    console.log('发送按钮存在');
}

waitFindOne() ​

返回: {UiObject} 出现后的节点

一直阻塞,直到屏幕上出现匹配节点。界面还在加载时用这个,不要空转 findOne。

find() ​

返回: {UiObject[]} 全部匹配节点

当前条件立刻查一遍,不等待。

findBy(uiSelector) ​

参数:

  • uiSelector {UiSelector} 在子树里继续用的条件

返回: {UiObject[]}

先按当前选择器得到集合,再在每个节点的子孙里找符合 uiSelector 的节点。

findBy(timeout) ​

参数:

  • timeout {number} 最长等待毫秒

返回: {UiObject[]}

和 find() 相同,但节点还没出现时最多等 timeout 毫秒。

findOne() ​

返回: {UiObject} 第一个匹配节点;没有则为空

立刻查一次,不会一直等。

同 id / 同文本在界面上可能有多份。点击前一般先用上面的 filter 去掉屏幕外节点,再 findOne。

findOnce() ​

返回: {UiObject} 第一个匹配节点

与 findOne() 相同。

findOne(uiSelector) ​

参数:

  • uiSelector {UiSelector} 子树条件

返回: {UiObject}

在当前匹配节点的子孙里找第一个符合条件的节点。

findOneBy(uiSelector) ​

参数:

  • uiSelector {UiSelector} 子树条件

返回: {UiObject}

类似 findBy,找到一个就返回。

findOneBy(timeout) ​

参数:

  • timeout {number} 最长等待毫秒

返回: {UiObject}

类似带超时的 findBy,找到一个就返回。

相关 ​