AutoJs6

- Overview - 综述
- About - 关于文档
- Progress - 文档部署进度
- Changelog - 文档更新日志

- Manual - AutoJs6 使用手册
- Q & A - 疑难解答

- Global - 全局对象
- Automator - 自动化
- AutoJs6 - 本体应用
- App - 通用应用
- Color - 颜色
- Image - 图像
- OCR - 光学字符识别
- Barcode - 条码
- QR Code - 二维码
- Keys - 按键
- Device - 设备
- Storage - 储存
- File - 文件
- Engine - 引擎
- Task - 任务
- Module - 模块
- Plugins - 插件
- Toast - 消息浮动框
- Notice - 消息通知
- Console - 控制台
- Shell
- Shizuku
- Media - 多媒体
- Sensor - 传感器
- Recorder - 记录器
- Timer - 定时器
- Thread - 线程
- Continuation - 协程
- Event - 事件监听
- Dialog - 对话框
- Floaty - 悬浮窗
- Canvas - 画布
- UI - 用户界面
- Web - 万维网
- HTTP
- Base64
- Crypto - 密文
- Internationalization - 国际化
- Standardization - 标准化
- E4X

- UiSelector - 选择器
- UiObject - 控件节点
- UiObjectCollection - 控件集合
- UiObjectActions - 控件节点行为
- WebSocket
- EventEmitter - 事件发射器
- ImageWrapper - 包装图像类
- App - 应用枚举类
- Color - 颜色类
- Version - 版本工具类
- Polyfill - 代码填泥
- Arrayx - Array 扩展
- Numberx - Number 扩展
- Mathx - Math 扩展

- Exceptions - 异常
- Intent - 意图
- Runtime - 运行时
- Context - 上下文
- Activity - 活动

- Scripting Java - 脚本化 Java
- Android API Level - 安卓 API 级别
- Color Table - 颜色列表

- Glossaries - 术语
- HttpHeader - HTTP 标头
- HttpRequestMethods - HTTP 请求方法
- MimeType - MIME 类型
- NotificationChannel - 通知渠道

- Data Types - 数据类型
- Omnipotent Types - 全能类型
- Storage - 存储类
- AndroidBundle
- AndroidRect
- CryptoCipherOptions
- CryptoKey
- CryptoKeyPair
- ConsoleBuildOptions
- HttpRequestBuilderOptions
- HttpRequestHeaders
- HttpResponseBody
- HttpResponseHeaders
- HttpResponse
- InjectableWebClient
- InjectableWebView
- NoticeOptions
- NoticeChannelOptions
- NoticePresetConfiguration
- NoticeBuilder
- Okhttp3HttpUrl
- OcrOptions
- Okhttp3Request
- OpencvPoint
- OpencvRect
- OpencvSize

- GitHub - 应用项目地址
- GitHub - 文档项目地址

# 控件节点 (UiObject)#

UiObject 通常被称为 [ 控件 / 节点 / 控件节点 ], 可看做是一个通过安卓无障碍服务包装的 AccessibilityNodeInfo 对象, 代表一个当前活动窗口中的节点, 通过此节点可收集控件信息或执行控件行为, 进而实现一系列自动化操作.

应用界面通常由控件构成, 如 ImageView 构成图像控件, TextView 构成文本控件. 通过不同的布局可决定不同控件的位置, 如 LinearLayout (线性布局) 按水平或垂直方式排布及显示控件, AbsListView (列表布局) 按列表方式排布及显示控件. 不同的布局方式形成了 控件层级.

控件拥有特定的属性, 可分为两种类型, 状态型及行为型.
行为型属性可参阅章节 控件节点行为 (UiObjectActions).
状态型属性访问均被封装为方法调用的形式, 如访问控件的类名, 需使用 `w.className()` 而非 `w.className`.

> 注: 在 AutoJs6 中, 由 UiObject 代表一个控件节点, 它继承自 AccessibilityNodeInfoCompat, 而并非一个 View.

UiObject

## [@] UiObject#

`Global`

如需获取一个 UiObject 对象, 通常使用 选择器 获取.

    /* 获取一个包含任意文本的 UiObject 对象. */
    let w = pickup(/.+/);

    /* 当活动窗口中不存在符合筛选条件的控件时返回 null. */
    console.log(w === null);

    /* 使用 instanceof 操作符查看对象 w 是否为 UiObject "类" 的实例. */
    console.log(w instanceof UiObject);

多数 UiObject 的实例方法 (如 parent 和 child 等) 均返回自身类型, 因此可实现链式调用:

    let w = pickup('hello');
    /* 获取 w 控件的三级父控件的 2 号索引子控件. */
    w.parent().parent().parent().child(2);

## [m#] parent#

### parent(i?)#

`[6.3.3]` `A11Y` `Overload [1-2]/2`

- [ i = `1` ] { number } - 相对级数
- returns { UiObject | null }

返回其父控件.

当指定级数 `i` 时, 返回其对应级数的父控件.

`i` 为 `0` 时, 返回控件自身,
`i` 为正整数时, 返回第 `i` 级父控件,
`i` 为负数时, 将抛出异常.

    let w = pickup(/.+/);
    w.parent();
    w.parent(1); /* 同上. */
    w.compass('p'); /* 同上. */
    detect(w, 'p'); /* 同上. */

    w.parent().parent().parent();
    w.parent(3); /* 同上. */
    w.compass('p3'); /* 同上. */
    detect(w, 'p3'); /* 同上. */

## [m#] child#

### child(i)#

`[6.3.3]` `A11Y`

- i { number } - 索引
- returns { UiObject | null }

返回其索引为 `i` 的子控件.

`i` 为正整数或 `0`, 返回正数索引子控件,
`i` 为负整数, 返回倒数索引子控件,

    let w = pickup(/.+/);
    w.child(3);
    w.compass('c3'); /* 同上. */
    detect(w, 'c3'); /* 同上. */

    w.child(3).child(1);
    w.compass('c3c1'); /* 同上. */
    detect(w, 'c3>1'); /* 同上. */

    w.child(-1); /* 最后一个子控件. */

    w.child(-2); /* 倒数第 2 个子控件. */
    w.compass('c-2'); /* 同上. */
    detect(w, 'c-2'); /* 同上. */

## [m#] firstChild#

### firstChild()#

`6.3.3` `A11Y`

- returns { UiObject }

返回第一个子控件.

相当于 `child(0)`.

## [m#] lastChild#

### lastChild()#

`6.3.3` `A11Y`

- returns { UiObject }

返回最后一个子控件.

相当于 `child(-1)`.

## [m#] childCount#

### childCount()#

`A11Y`

- returns { number }

返回当前节点的子控件数量.

别名属性或方法:

- `[m#]` getChildCount

## [m#] hasChildren#

### hasChildren()#

`6.2.0` `A11Y`

- returns { boolean }

返回当前节点是否有子节点.

相当于 `childCount() > 0`.

## [m#] children#

### children()#

`A11Y`

- returns { UiObjectCollection }

返回当前节点的子控件集合.

    let cc = pickup({ filter: w => w.children().length > 5 }, 'children');

    console.log(cc.length); /* e.g. 10 */

    cc.forEach((w) => {
        let content = w.content();
        content && console.log(content);
    })

如需返回当前节点下的所有子孙控件集合, 可使用 UiObject#find().

    let w = pickup({ filter: w => w.children().length > 5 });
    console.log(w.find().length); /* e.g. 20 */

## [m#] sibling#

### sibling(i)#

`6.3.3` `A11Y`

- i { number } - 索引
- returns { UiObject | null }

返回其索引为 `i` 的兄弟控件.

`i` 为正整数或 `0`, 返回正数索引兄弟控件,
`i` 为负整数, 返回倒数索引兄弟控件,

当 `i` 与 indexInParent() 相同时, 返回其自身.

    let w = pickup(/.+/);
    w.sibling(0); /* 第 1 (索引为 0) 的兄弟控件. */
    w.compass('s0'); /* 同上. */
    detect(w, 's0'); /* 同上. */

    w.sibling(-2); /* 倒数第 2 个兄弟控件. */
    w.compass('s-2'); /* 同上. */
    detect(w, 's-2'); /* 同上. */

如需获取相邻的兄弟控件, 可使用 offset, 或使用 nextSibling 与 previousSibling.

## [m#] firstSibling#

### firstSibling()#

`6.3.3` `A11Y`

- returns { UiObject }

返回第一个兄弟控件 (可能为自身).

相当于 `sibling(0)`.

## [m#] lastSibling#

### lastSibling()#

`6.3.3` `A11Y`

- returns { UiObject }

返回最后一个兄弟控件 (可能为自身).

相当于 `sibling(-1)`.

## [m#] offset#

### offset(i)#

`6.3.3` `A11Y`

- i { number } - 索引偏移量
- returns { UiObject | null }

返回其索引偏移量为 `i` 的兄弟控件.

`i` 为正整数, 返回后向兄弟控件,
`i` 为负整数, 返回前向兄弟控件,
`i` 为 `0`, 返回当前控件自身.

    let w = pickup(/.+/);
    w.offset(3);
    w.compass('s>3'); /* 同上. */
    detect(w, 's>3'); /* 同上. */

    w.offset(-2);
    w.compass('s<2'); /* 同上. */
    detect(w, 's<2'); /* 同上. */

如需获取相邻的兄弟控件, 除 offset 外, 还可使用 nextSibling 与 previousSibling.

## [m#] nextSibling#

### nextSibling()#

`6.3.3` `A11Y`

- returns { UiObject | null }

返回后一个兄弟控件.

相当于 `offset(1)`.

## [m#] previousSibling#

### previousSibling()#

`6.3.3` `A11Y`

- returns { UiObject | null }

返回前一个兄弟控件.

相当于 `offset(-1)`.

## [m#] siblingCount#

### siblingCount()#

`6.3.3` `A11Y`

- returns { number }

返回当前节点的兄弟控件总数量 (含自身).

`siblingCount` 返回一个总是大于等于 `1` 的数字.

## [m#] isSingleton#

### isSingleton()#

`6.3.3` `A11Y`

- returns { boolean }

返回当前节点是否为独身节点, 即除自身外没有其他兄弟节点.

相当于 `siblingCount() === 1`.

## [m#] siblings#

### siblings()#

`6.3.3` `A11Y`

- returns { UiObjectCollection }

返回当前节点的兄弟控件集合 (含自身).

## [m#] indexInParent#

### indexInParent()#

`A11Y`

- returns { number }

返回当前节点在其父控件的索引值.

    /* 例如 p 控件有 3 个子控件 (a, b, c). */

    a.indexInParent(); // 0
    p.child(0); /* 对应 a. */

    console.log(c.indexInParent()); // 2
    p.child(2); /* 对应 c. */

方法 `indexInParent` 通常用于访问临近或相对位置的兄弟节点:

    /* 例如 p 控件有 3 个子控件 (a, b, c). */

    /* c 是 b 的相邻兄弟节点 (相对索引为 1). */
    p.child(b.indexInParent() + 1); /* 对应 c. */
    b.compass('s>1'); /* 使用罗盘方法, 效果同上. */

    /* a 也是 b 的相邻兄弟节点 (相对索引为 -1). */
    p.child(b.indexInParent() - 1); /* 对应 a. */
    b.compass('s<1'); /* 使用罗盘方法, 效果同上. */

    /* a 是 c 的兄弟节点 (相对索引为 -2). */
    p.child(c.indexInParent() - 2); /* 对应 a. */
    b.compass('s<2'); /* 使用罗盘方法, 效果同上. */

有时也需要获取当前节点的父控件在其父控件的索引值:

    let p = pickup({ filter: w => w.depth() > 0 && w.parent().indexInParent() > 0 });
    console.log(p.parent().indexInParent()); // e.g. 2

## [m#] find#

### find()#

`Overload 1/2` `A11Y`

- returns { UiObjectCollection }

以当前节点作为根节点, 返回其所有的子孙控件集合.

与 children 方法不同, `w.children()` 返回子控件集合, 而 `w.find()` 返回所有子孙控件集合.

    let root = depth(0).findOnce();
    console.log(root.find().length); // e.g. 500
    console.log(root.children().length); // e.g. 2

子孙控件集合中包含根节点本身:

    /* 找出一个没有任何子孙控件的节点. */
    let w = pickup({ filter: w => w.childCount() === 0 });

    /* find() 返回的集合包含其自身, 而非空集合. */
    console.log(w.find().length); // 1

因此, `N 层级子孙控件集合数量` = `N + 1 层级子孙控件数量总和` + `1`:

    let root = depth(0).findOnce();
    let sumA = root.find().length;
    let sumB = root.children().reduce((sum, c) => sum + c.find().length, 0);
    console.log(sumA, sumB); /* sumA 和 sumB 相差 1. */

### find(selector)#

`Overload 2/2` `A11Y`

- selector { selector } - 选择器
- returns { UiObjectCollection }

以当前节点作为根节点, 返回其所有满足选择器筛选条件的子孙控件集合.

    /* 找出 w 控件下所有符合有效内容长度不小于 10 的子孙控件集合. */
    console.log(w.find(contentMatch(/\s*.{10,}\s*/)));

## [m#] findOne#

### findOne(selector)#

`A11Y`

- selector { selector } - 选择器
- returns { UiObject }

以当前节点作为根节点, 在其所有子孙控件中找出一个满足选择器筛选条件的控件.

    /* 找出 w 子孙控件中符合有效内容长度不小于 10 的一个控件. */
    console.log(w.findOne(contentMatch(/\s*.{10,}\s*/)));

## [m#] bounds#

### bounds()#

`A11Y`

- returns { AndroidRect }

方法 boundsInScreen 的别名.

返回一个 控件矩形 (Rect), 表示控件在屏幕的相对位置及空间范围.

    let bounds = contentMatch(/.+/).findOnce().bounds();
    console.log(bounds); // e.g. Rect(0, 48 - 112, 160)

别名属性或方法:

- `[m#]` boundsInScreen

## [m#] boundsInScreen#

### boundsInScreen()#

`A11Y`

- returns { AndroidRect }

返回一个 控件矩形 (Rect), 表示控件在屏幕的相对位置及空间范围.

    let bounds = contentMatch(/.+/).findOnce().boundsInScreen();
    console.log(bounds); // e.g. Rect(0, 48 - 112, 160)

别名属性或方法:

- `[m#]` bounds

## [m#] boundsInParent#

### boundsInParent()#

`A11Y`

`DEPRECATED`

- returns { AndroidRect }

返回一个 控件矩形 (Rect), 表示控件于其父控件的相对位置及空间范围.

因其父控件实际上是 `View#getParentForAccessibility()` 的结果, 而非此控件的 `viewParent`, 所以得到的结果是不可靠的.

    let bounds = contentMatch(/.+/).findOnce().boundsInParent();
    console.log(bounds); // e.g. Rect(0, 0 - 112, 112)

## [m#] boundsLeft#

### boundsLeft()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形左边界距屏幕左边缘的像素距离.

    let w = pickup(/.+/);
    console.log(w.bounds()); // e.g. Rect(0, 48 - 112, 160)
    console.log(w.bounds().left); // e.g. 0
    console.log(w.boundsLeft()); // e.g. 0
    console.log(w.left()); // e.g. 0

## [m#] boundsTop#

### boundsTop()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形上边界距屏幕上边缘的像素距离.

    let w = pickup(/.+/);
    console.log(w.bounds()); // e.g. Rect(0, 48 - 112, 160)
    console.log(w.bounds().top); // e.g. 48
    console.log(w.boundsTop()); // e.g. 48
    console.log(w.top()); // e.g. 48

## [m#] boundsRight#

### boundsRight()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形右边界距屏幕左边缘的像素距离.

    let w = pickup(/.+/);
    console.log(w.bounds()); // e.g. Rect(0, 48 - 112, 160)
    console.log(w.bounds().right); // e.g. 112
    console.log(w.right()); // e.g. 112
    console.log(w.boundsRight()); // e.g. 112

## [m#] boundsBottom#

### boundsBottom()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形下边界距屏幕上边缘的像素距离.

    let w = pickup(/.+/);
    console.log(w.bounds()); // e.g. Rect(0, 48 - 112, 160)
    console.log(w.bounds().bottom); // e.g. 160
    console.log(w.bottom()); // e.g. 160
    console.log(w.boundsBottom()); // e.g. 160

## [m#] boundsWidth#

### boundsWidth()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的宽度.

    let w = pickup(/.+/);
    console.log(w.bounds()); // e.g. Rect(0, 48 - 112, 160)
    console.log(w.bounds().width()); // e.g. 112
    console.log(w.boundsWidth()); // e.g. 112
    console.log(w.right() - w.left()); // e.g. 112

## [m#] boundsHeight#

### boundsHeight()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的高度.

    let w = pickup(/.+/);
    console.log(w.bounds()); // e.g. Rect(0, 48 - 112, 160)
    console.log(w.bounds().height()); // e.g. 112
    console.log(w.boundsHeight()); // e.g. 112
    console.log(w.bottom() - w.top()); // e.g. 112

## [m#] boundsCenterX#

### boundsCenterX()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的中心 X 坐标 (中心点距屏幕左边缘的像素距离).

该坐标为整数, 非整数数值将按 向下取整 处理, 因此会损失精度.

如需保留精度, 可使用 boundsExactCenterX.

    let wA = pickup(/.+/);
    console.log(wA.bounds()); // e.g. Rect(0, 48 - 112, 160)
    console.log(wA.bounds().centerX()); // e.g. 56
    console.log(wA.boundsCenterX()); // e.g. 56

    let wB = pickup(/.+/);
    console.log(wB.bounds()); // e.g. Rect(0, 0 - 11, 20)
    console.log(wB.boundsCenterX()); // e.g. 5 (5.5 向下取整得 5)

    let wC = pickup(/.+/);
    console.log(wC.bounds()); // e.g. Rect(0, 0 - -11, 20)
    console.log(wC.boundsCenterX()); // e.g. -6 (-5.5 向下取整得 -6)

## [m#] boundsExactCenterX#

### boundsExactCenterX()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的中心 X 坐标 (中心点距屏幕左边缘的像素距离).

该坐标将保留精度 (可能为非整数), 如需返回整数结果, 可使用 boundsCenterX.

    let wA = pickup(/.+/);
    console.log(wA.bounds()); // e.g. Rect(0, 48 - 112, 160)
    console.log(wA.bounds().exactCenterX()); // e.g. 56
    console.log(wA.boundsExactCenterX()); // e.g. 56

    let wB = pickup(/.+/);
    console.log(wB.bounds()); // e.g. Rect(0, 0 - 11, 20)
    console.log(wB.boundsExactCenterX()); // e.g. 5.5

    let wC = pickup(/.+/);
    console.log(wC.bounds()); // e.g. Rect(0, 0 - -11, 20)
    console.log(wC.boundsExactCenterX()); // e.g. -5.5

## [m#] boundsCenterY#

### boundsCenterY()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的中心 Y 坐标 (中心点距屏幕上边缘的像素距离).

该坐标为整数, 非整数数值将按 向下取整 处理, 因此会损失精度.

如需保留精度, 可使用 boundsExactCenterY.

    let wA = pickup(/.+/);
    console.log(wA.bounds()); // e.g. Rect(0, 48 - 112, 160)
    console.log(wA.bounds().centerY()); // e.g. 104
    console.log(wA.boundsCenterY()); // e.g. 104

    let wB = pickup(/.+/);
    console.log(wB.bounds()); // e.g. Rect(0, 0 - 11, 33)
    console.log(wB.boundsCenterY()); // e.g. 16 (16.5 向下取整得 16)

    let wC = pickup(/.+/);
    console.log(wC.bounds()); // e.g. Rect(0, 0 - 11, -33)
    console.log(wC.boundsCenterY()); // e.g. -17 (-16.5 向下取整得 -17)

## [m#] boundsExactCenterY#

### boundsExactCenterY()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的中心 Y 坐标 (中心点距屏幕上边缘的像素距离).

该坐标将保留精度 (可能为非整数), 如需返回整数结果, 可使用 boundsCenterY.

    let wA = pickup(/.+/);
    console.log(wA.bounds()); // e.g. Rect(0, 48 - 112, 160)
    console.log(wA.bounds().exactCenterY()); // e.g. 104
    console.log(wA.boundsExactCenterY()); // e.g. 104

    let wB = pickup(/.+/);
    console.log(wB.bounds()); // e.g. Rect(0, 0 - 11, 33)
    console.log(wB.boundsExactCenterY()); // e.g. 16.5

    let wC = pickup(/.+/);
    console.log(wC.bounds()); // e.g. Rect(0, 0 - 11, -33)
    console.log(wC.boundsExactCenterY()); // e.g. -16.5

## [m#] left#

### left()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形左边界距屏幕左边缘的像素距离.

UiObject#boundsLeft 的别名方法.

## [m#] top#

### top()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形上边界距屏幕上边缘的像素距离.

UiObject#boundsTop 的别名方法.

## [m#] right#

### right()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形右边界距屏幕左边缘的像素距离.

UiObject#boundsRight 的别名方法.

## [m#] bottom#

### bottom()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形下边界距屏幕上边缘的像素距离.

UiObject#boundsBottom 的别名方法.

## [m#] width#

### width()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的宽度.

UiObject#boundsWidth 的别名方法.

## [m#] height#

### height()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的高度.

UiObject#boundsHeight 的别名方法.

## [m#] centerX#

### centerX()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的中心 X 坐标 (中心点距屏幕左边缘的像素距离).

UiObject#boundsCenterX 的别名方法.

## [m#] exactCenterX#

### exactCenterX()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的中心 X 坐标 (中心点距屏幕左边缘的像素距离).

UiObject#boundsExactCenterX 的别名方法.

## [m#] centerY#

### centerY()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的中心 Y 坐标 (中心点距屏幕上边缘的像素距离).

UiObject#boundsCenterY 的别名方法.

## [m#] exactCenterY#

### exactCenterY()#

`6.2.0` `A11Y`

- returns { number }

返回控件矩形的中心 Y 坐标 (中心点距屏幕上边缘的像素距离).

UiObject#boundsExactCenterY 的别名方法.

## [m#] point#

### point()#

`6.2.0` `A11Y`

- returns { OpencvPoint }

返回控件矩形的中心点 (Point).

该中心点坐标由 exactCenterX 和 exactCenterY 计算获得, 因此会保留精度.

    let wA = pickup(/.+/);
    console.log(wA.bounds()); // e.g. Rect(0, 0 - 10, 12)
    console.log(wA.point()); // e.g. {5.0, 6.0}
    console.log(wA.point().x); // e.g. 5

    let wB = pickup(/.+/);
    console.log(wB.bounds()); // e.g. Rect(0, 0 - 11, 13)
    console.log(wB.point()); // e.g. {5.5, 6.5}
    console.log(wB.point().y); // e.g. 6.5

## [m#] size#

### size()#

`6.2.0` `A11Y`

- returns { OpencvSize }

返回控件矩形的尺寸 (Size).

    let w = pickup(/.+/);
    console.log(w.bounds()); // e.g. Rect(0, 0 - 10, 12)
    console.log(w.size()); // e.g. 10x12
    console.log(w.size().width); // e.g. 10
    console.log(w.size().height); // e.g. 12

## [m#] clickBounds#

### clickBounds(offsetX?, offsetY?)#

`6.2.0` `Overload [1-3]/3` `A11Y`

- [ offsetX = 0 ] { number } - X 坐标偏移量 (支持负值及百分率)
- [ offsetY = 0 ] { number } - Y 坐标偏移量 (支持负值及百分率)
- returns { boolean } - 是否点击行为已执行且执行过程中无异常

点击控件矩形的中心点坐标.

点击操作借助 automator.click(x, y) 完成, 此操作需要启用无障碍服务.

    let w = pickup(/.+/);

    console.log(w.bounds()); // e.g. Rect(0, 60 - 100, 200)

    w.clickBounds(); /* 相当于 click(50, 130) . */
    click(w.centerX(), w.centerY()); /* 效果同上. */

    w.clickBounds(10); /* X 坐标偏移量为 10 像素, 相当于 click(50 + 10, 130) . */
    w.clickBounds(10, 15); /* X 与 Y 坐标偏移量分别为 10 和 15 像素, 相当于 click(50 + 10, 130 + 15) . */
    w.clickBounds(0, -15); /* Y 坐标偏移量为 -15 像素, 相当于 click(50, 130 - 15) . */
    w.clickBounds(0.2); /* X 坐标偏移量为 20% 屏幕宽度, 相当于 click(50 + 0.2 * device.width, 130) . */
    w.clickBounds(0.2, -0.05); /* X 与 Y 坐标偏移量为 20% 屏幕宽度和 -5% 屏幕高度. */

## [m#] id#

### id()#

`A11Y`

- returns { string | null }

返回节点的 ID 资源全称 (Fully-Qualified ID Resource Name).

若 ID 不存在, 返回 null.

安卓资源全称格式为 `package:type/entry`, 即 `包名:类型/资源项`.
ID 资源全称的 `类型` 为 `id`.
一个有效的 ID 资源全称: `com.test:id/some_entry`.

    console.log(idMatch(/.+/).findOnce().id()); // e.g. org.autojs.autojs6:id/action_bar_root
    console.log(idMatch(/.+/).findOnce().fullId()); /* 同上. */
    console.log(idMatch(/.+/).findOnce().getViewIdResourceName()); /* 同上. */

需额外留意, 部分应用的控件 ID 资源全称可能不符合标准:

    /* 标准 ID 全称. */
    let canonicalId = "com.test:id/hello_world";

    /* 可能出现的非标准 ID 全称. */
    let peculiarId = "hello_world"; /* 仅含资源项, 无包名及类型标识. */

别名属性或方法:

- `[m#]` getViewIdResourceName
- `[m#]` fullId

## [m#] fullId#

### fullId()#

`6.2.0` `A11Y`

- returns { string | null }

返回节点的 ID 资源全称 (Fully-Qualified ID Resource Name).

若 ID 不存在, 返回 null.

UiObject#id 的别名方法.

## [m#] idEntry#

### idEntry()#

`6.2.0` `A11Y`

- returns { string | null }

返回节点的 ID 资源项名称 (ID Resource Entry Name).

安卓资源全称格式为 `package:type/entry`, 即 `包名:类型/资源项`.
例如对于 ID 资源全称 `com.test:id/some_entry`, 其 ID 资源项名称为 `some_entry`.

    /* ID 资源全称. */
    console.log(idMatch(/.+/).findOnce().id()); // e.g. org.autojs.autojs6:id/action_bar_root

    /* ID 资源项名称. */
    console.log(idMatch(/.+/).findOnce().idEntry()); // action_bar_root
    console.log(idMatch(/.+/).findOnce().simpleId()); /* 同上. */

别名属性或方法:

- `[m#]` simpleId

## [m#] simpleId#

### simpleId()#

`6.2.0` `A11Y`

- returns { string | null }

返回节点的 ID 资源项名称 (ID Resource Entry Name).

若 ID 不存在, 返回 null.

UiObject#idEntry 的别名方法.

## [m#] idHex#

### idHex()#

`A11Y`

- returns { string | null }

返回节点的 ID 资源全称 的 资源 ID 十六进制字符串值, 简称 `ID 资源十六进制代表值`.

1. 获取 `ID 资源全称` 对应的 `资源 ID`
2. 将 `资源 ID` 的十六进制值以 `0x` 作为前缀进行组合
3. 返回组合的字符串值

若 ID 不存在, 返回 null.

    console.log(idMatch(/explorer_item_list/).findOnce().idHex()); /* e.g. 0x7f090117 */

## [m#] text#

### text()#

`A11Y`

- returns { string }

返回控件文本内容.

若文本内容不存在, 返回空字符串.

出于保护隐私目的, `isPassword()` 返回 `true` 的密码类型控件, `text()` 将返回空字符串.

    console.log(textMatch(/.+/).findOnce().text()); /* e.g. hello */

别名属性或方法:

- `[m#]` getText

## [m#] desc#

### desc()#

`A11Y`

- returns { string | null }

返回控件的内容描述标签.

若内容描述标签容不存在, 返回 null.

内容描述标签可以帮助需要无障碍服务的用户 (如视力障碍人群等) 理解当前控件的用途或说明.
如 TalkBack 开启后可以朗读控件的内容描述标签, 对于理解那些没有文本内容的控件尤其重要.

    console.log(descMatch(/.+/).findOnce().desc()); /* e.g. Restart icon */

别名属性或方法:

- `[m#]` getContentDescription

## [m#] content#

### content()#

`A11Y`

- returns { string }

返回控件内容 (包括内容描述标签或本文内容).

若无内容, 返回空字符串.

`content` 方法相当于 `w.desc() || w.text()`, 即优先获取 desc 返回的内容, 若为 null, 继续获取 text 返回的内容.

    console.log(contentMatch(/.+/).findOnce().content()); /* e.g. Avatar */

## [m#] className#

### className()#

`A11Y`

- returns { string | null }

返回控件的类名.

若如类名, 返回 null.

    console.log(classNameMatch(/.+/).findOnce().className()); /* e.g. android.widget.EditText */

常见类名:

- android.view.View
- android.view.ViewGroup
- android.widget.ImageView
- android.widget.ImageButton
- android.widget.Button
- android.widget.ScrollView
- android.widget.TextView
- android.widget.EditText
- android.widget.Switch
- android.widget.LinearLayout
- android.widget.FrameLayout
- android.widget.RelativeLayout

别名属性或方法:

- `[m#]` getClassName

## [m#] packageName#

### packageName()#

`A11Y`

- returns { string | null }

返回控件的包名.

若如包名, 返回 null.

    console.log(packageNameMatch(/.+/).findOnce().packageName()); /* e.g. org.autojs.autojs6 */

别名属性或方法:

- `[m#]` getPackageName

## [m#] depth#

### depth()#

`A11Y`

- returns { number }

返回 控件层级 深度.

顶层控件 (只有一个) 的深度值为 0, 次级控件 (可能有多个) 的深度值全部为 1, 以此类推.

    console.log(findOnce().depth()); // 0
    console.log(contentMatch(/.+/).depth()); /* e.g. 5 */

## [m#] checkable#

### checkable()#

`A11Y`

- returns { boolean }

返回控件是否可勾选.

别名属性或方法:

- `[m#]` isCheckable

关联属性或方法:

- 检查状态
  - `[m#]` checked (isChecked)
- 检查可用性
  - `[m#]` checkable (isCheckable)

## [m#] checked#

### checked()#

`A11Y`

- returns { boolean }

返回控件是否已勾选.

别名属性或方法:

- `[m#]` isChecked

关联属性或方法:

- 检查状态
  - `[m#]` checked (isChecked)
- 检查可用性
  - `[m#]` checkable (isCheckable)

## [m#] focusable#

### focusable()#

`A11Y`

- returns { boolean }

返回控件是否可聚焦.

别名属性或方法:

- `[m#]` isFocusable

关联属性或方法:

- 检查状态
  - `[m#]` focused (isFocused)
- 检查可用性
  - `[m#]` focusable (isFocusable)

## [m#] focused#

### focused()#

`A11Y`

- returns { boolean }

返回控件是否已聚焦.

别名属性或方法:

- `[m#]` isFocused

关联属性或方法:

- 检查状态
  - `[m#]` focused (isFocused)
- 检查可用性
  - `[m#]` focusable (isFocusable)

## [m#] visibleToUser#

### visibleToUser()#

`A11Y`

- returns { boolean }

返回控件是否对用户可见.

别名属性或方法:

- `[m#]` isVisibleToUser

## [m#] accessibilityFocused#

### accessibilityFocused()#

`A11Y`

- returns { boolean }

返回控件是否已获取无障碍焦点.

别名属性或方法:

- `[m#]` isAccessibilityFocused

关联属性或方法:

- 检查状态
  - `[m#]` accessibilityFocused (isAccessibilityFocused)
- 执行行为
  - `[m#]` accessibilityFocus

## [m#] selected#

### selected()#

`A11Y`

- returns { boolean }

返回控件是否已选中.

别名属性或方法:

- `[m#]` isSelected

关联属性或方法:

- 检查状态
  - `[m#]` selected (isSelected)
- 执行行为
  - `[m#]` select

## [m#] clickable#

### clickable()#

`A11Y`

- returns { boolean }

返回控件是否可点击.

别名属性或方法:

- `[m#]` isClickable

关联属性或方法:

- 检查状态
  - `[m#]` clickable (isClickable)
- 执行行为
  - `[m#]` click

## [m#] longClickable#

### longClickable()#

`A11Y`

- returns { boolean }

返回控件是否可长按.

别名属性或方法:

- `[m#]` isLongClickable

关联属性或方法:

- 检查状态
  - `[m#]` longClickable (isLongClickable)
- 执行行为
  - `[m#]` longClick

## [m#] enabled#

### enabled()#

`A11Y`

- returns { boolean }

返回控件是否启用 (未被禁用).

别名属性或方法:

- `[m#]` isEnabled

## [m#] password#

### password()#

`A11Y`

- returns { boolean }

返回控件是否是密码型控件.

别名属性或方法:

- `[m#]` isPassword

## [m#] scrollable#

### scrollable()#

`A11Y`

- returns { boolean }

返回控件是否可滚动.

别名属性或方法:

- `[m#]` isScrollable

关联属性或方法:

- 检查状态
  - `[m#]` scrollable (isScrollable)
- 执行行为
  - `[m#]` scrollBackward
  - `[m#]` scrollDown
  - `[m#]` scrollForward
  - `[m#]` scrollLeft
  - `[m#]` scrollRight
  - `[m#]` scrollTo
  - `[m#]` scrollUp

## [m#] editable#

### editable()#

`6.2.0` `A11Y`

- returns { boolean }

返回控件是否可编辑.

别名属性或方法:

- `[m#]` isEditable

## [m#] rowCount#

### rowCount()#

`A11Y`

- returns { boolean }

返回 信息集控件 的行数.

## [m#] columnCount#

### columnCount()#

`A11Y`

- returns { boolean }

返回 信息集控件 的列数.

## [m#] row#

### row()#

`A11Y`

- returns { boolean }

返回 子项信息集控件 所在行的索引值.

## [m#] column#

### column()#

`A11Y`

- returns { boolean }

返回 子项信息集控件 所在列的索引值.

## [m#] rowSpan#

### rowSpan()#

`A11Y`

- returns { boolean }

返回 子项信息集控件 纵跨的行数.

## [m#] columnSpan#

### columnSpan()#

`A11Y`

- returns { boolean }

返回 子项信息集控件 横跨的列数.

## [m#] drawingOrder#

### drawingOrder()#

`A11Y`

- returns { number }

返回节点的视图绘制次序.

此次序由其父节点决定, 是一个相对于其兄弟节点的索引值.
在某些情况下, 视图 (View) 绘制的过程本质上是同时发生的, 两个兄弟节点可能返回同一个索引值, 甚至此索引值可能被忽略 (返回默认值 0).

    console.log(pickup(/.+/).drawingOrder()); // e.g. 0

## [m#] actionNames#

### actionNames()#

`A11Y`

- returns { string[] }

返回控件支持的 控件行为 数组.

    let w = pickup(/.+/);

    /* e.g. [ ACTION_CLICK, ACTION_SET_SELECTION, ACTION_FOCUS ] */
    console.log(w.actionNames());

上述示例, 数组中的三个元素代表控件可以执行对应的行为, 即 `w.click()`, `w.setSelection(...)` 及 `w.focus()`.

数组中的元素均为 "ACTION_" 开头的控件行为 ID 的字符串形式.
更多控件行为 ID 可参阅 控件节点行为 章节的 `行为 ID` 表格.

如需判断一个控件是否支持一个或多个行为, 可使用 hasAction 方法.

## [m#] hasAction#

### hasAction(...actions)#

`A11Y`

- actions { ...string[] }
- returns { boolean }

返回控件是否 全部支持 指定的一个或多个 控件行为.

参数 actions 是 可变参数, 均满足 "ACTION_" 开头的控件行为 ID 的字符串形式 ("ACTION_" 可省略).

    let w = pickup(/.+/);

    /* 判断 w 是否可点击. */
    console.log(w.hasAction("ACTION_CLICK"));
    console.log(w.hasAction("CLICK")); /* ACTION_ 前缀可省略. */

    /* 判断 w 是否可点击, 可聚焦, 可设置文本. */
    console.log(w.hasAction("ACTION_CLICK", "ACTION_FOCUS", "ACTION_SET_TEXT"));
    console.log(w.hasAction("CLICK", "FOCUS", "SET_TEXT")); /* ACTION_ 前缀可省略. */

更多控件行为 ID 可参阅 控件节点行为 章节的 `行为 ID` 表格.

## [m#] performAction#

用于执行指定的控件行为.
在 控件节点行为 章节已详细描述相关内容, 此处仅注明几个重载方法的签名, 相关内容将不再赘述.

### performAction(action, ...arguments)#

`Overload 1/2` `A11Y`

- action { number } - 行为的唯一标志符 (Action ID)
- arguments { ...ActionArgument[] } - 行为参数, 用于给行为传递参数
- returns { boolean } - 是否行为已执行且执行过程中无异常

### performAction(action, bundle)#

`Overload 2/2` `A11Y`

- action { number } - 行为的唯一标志符 (Action ID)
- bundle { AndroidBundle } - 行为参数容器, 用于给行为传递参数
- returns { boolean } - 是否行为已执行且执行过程中无异常

## [m#] click#

### click()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 点击 ] 行为.

## [m#] longClick#

### longClick()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 长按 ] 行为.

## [m#] accessibilityFocus#

### accessibilityFocus()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 获取无障碍焦点 ] 行为.

## [m#] clearAccessibilityFocus#

### clearAccessibilityFocus()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 清除无障碍焦点 ] 行为.

## [m#] focus#

### focus()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 获取焦点 ] 行为.

## [m#] clearFocus#

### clearFocus()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 清除焦点 ] 行为.

## [m#] dragStart#

### dragStart()#

`6.2.0` `A11Y` `API>=32`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 拖放开始 ] 行为.

## [m#] dragDrop#

### dragDrop()#

`6.2.0` `A11Y` `API>=32`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 拖放放下 ] 行为.

## [m#] dragCancel#

### dragCancel()#

`6.2.0` `A11Y` `API>=32`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 拖放取消 ] 行为.

## [m#] imeEnter#

### imeEnter()#

`6.2.0` `A11Y` `API>=30`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 输入法 ENTER 键 ] 行为.

## [m#] moveWindow#

### moveWindow(x, y)#

`6.2.0` `A11Y` `API>=26`

- x { number } - X 坐标
- y { number } - Y 坐标
- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 移动窗口到新位置 ] 行为.

## [m#] nextAtMovementGranularity#

### nextAtMovementGranularity(granularity, isExtendSelection)#

`6.2.0` `A11Y`

- granularity { number } - 粒度
- isExtendSelection { boolean } - 是否扩展选则文本
- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 按粒度移至下一位置 ] 行为.

## [m#] nextHtmlElement#

### nextHtmlElement(element)#

`6.2.0` `A11Y`

- element { string } - 元素名称
- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 按元素移至下一位置 ] 行为.

## [m#] pageLeft#

### pageLeft()#

`6.2.0` `A11Y` `API>=29`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 使视窗左移的翻页 ] 行为.

## [m#] pageUp#

### pageUp()#

`6.2.0` `A11Y` `API>=29`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 使视窗上移的翻页 ] 行为.

## [m#] pageRight#

### pageRight()#

`6.2.0` `A11Y` `API>=29`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 使视窗右移的翻页 ] 行为.

## [m#] pageDown#

### pageDown()#

`6.2.0` `A11Y` `API>=29`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 使视窗下移的翻页 ] 行为.

## [m#] pressAndHold#

### pressAndHold()#

`6.2.0` `A11Y` `API>=30`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 按住 ] 行为.

## [m#] previousAtMovementGranularity#

### previousAtMovementGranularity(granularity, isExtendSelection)#

`6.2.0` `A11Y`

- granularity { number } - 粒度
- isExtendSelection { boolean } - 是否扩展选则文本
- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 按粒度移至上一位置 ] 行为.

## [m#] previousHtmlElement#

### previousHtmlElement(element)#

`6.2.0` `A11Y`

- element { string } - 元素名称
- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 按元素移至上一位置 ] 行为.

## [m#] showTextSuggestions#

### showTextSuggestions()#

`6.2.0` `A11Y` `API>=33`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 显示文本建议 ] 行为.

## [m#] showTooltip#

### showTooltip()#

`6.2.0` `A11Y` `API>=28`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 显示工具提示信息 ] 行为.

## [m#] hideTooltip#

### hideTooltip()#

`6.2.0` `A11Y` `API>=28`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 隐藏工具提示信息 ] 行为.

## [m#] show#

### show()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 显示在视窗内 ] 行为.

## [m#] dismiss#

### dismiss()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 消隐 ] 行为.

## [m#] copy#

### copy()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 复制文本 ] 行为.

## [m#] cut#

### cut()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 剪切文本 ] 行为.

## [m#] paste#

### paste()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 粘贴文本 ] 行为.

## [m#] select#

### select()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 选中 ] 行为.

## [m#] expand#

### expand()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 展开 ] 行为.

## [m#] collapse#

### collapse()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 折叠 ] 行为.

## [m#] scrollLeft#

### scrollLeft()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 使视窗左移的滚动 ] 行为.

## [m#] scrollUp#

### scrollUp()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 使视窗上移的滚动 ] 行为.

## [m#] scrollRight#

### scrollRight()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 使视窗右移的滚动 ] 行为.

## [m#] scrollDown#

### scrollDown()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 使视窗下移的滚动 ] 行为.

## [m#] scrollForward#

### scrollForward()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 使视窗前移的滚动 ] 行为.

## [m#] scrollBackward#

### scrollBackward()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 使视窗后移的滚动 ] 行为.

## [m#] scrollTo#

### scrollTo(row, column)#

`A11Y`

- row { number } - 行序数
- column { number } - 列序数
- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 将指定位置滚动至视窗内 ] 行为.

## [m#] contextClick#

### contextClick()#

`A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 上下文点击 ] 行为.

## [m#] setText#

### setText(text)#

`A11Y`

- text { string } - 文本
- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 设置文本 ] 行为.

## [m#] setSelection#

### setSelection(start, end)#

`A11Y`

- start { number } - 开始位置
- end { number } - 结束位置
- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 选择文本 ] 行为.

## [m#] clearSelection#

### clearSelection()#

`6.2.0` `A11Y`

- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 取消选择文本 ] 行为.

## [m#] setProgress#

### setProgress(progress)#

`A11Y`

- progress { number } - 进度值
- returns { boolean } - 是否行为已执行且执行过程中无异常

控件节点执行 [ 设置进度值 ] 行为.

## [m#] compass#

### compass(compassArg)#

`6.2.0` `A11Y`

- compassArg { DetectCompass } - 罗盘参数, 用于控制罗盘定位
- returns { UiObject | null } - 罗盘最终定位的控件节点

返回罗盘最终定位的 控件节点, 若定位失败, 返回 null.

罗盘定位类似于在 控件层级 中自由移动, 最终定位在某个指定的控件节点上.

    let w = clickable().findOnce();

    console.log(w.parent()); /* 父控件. */
    console.log(w.parent().parent()); /* 二级父控件. */
    console.log(w.child(0)); /* 索引 0 (首个) 子控件. */
    console.log(w.child(2)); /* 索引 2 子控件. */
    console.log(w.child(w.childCount() - 1)); /* 末尾子控件. */
    console.log(w.parent().child(5)); /* 索引 5 兄弟控件. */
    console.log(w.parent().child(w.childCount() - 2)); /* 倒数第 2 兄弟控件. */
    console.log(w.parent().child(w.indexInParent() - 1)); /* 相邻左侧兄弟节点. */
    console.log(w.parent().child(w.indexInParent() + 1)); /* 相邻右侧兄弟节点. */
    console.log(w.parent().parent().parent().parent().child(0).child(1).child(1).child(0)); /* 多级访问. */

    /* 使用控件罗盘替代上述所有语句. */

    console.log(w.compass('p')); /* 父控件. */
    console.log(w.compass('p2')); /* 二级父控件. */
    console.log(w.compass('c0')); /* 索引 0 (首个) 子控件. */
    console.log(w.compass('c2')); /* 索引 2 子控件. */
    console.log(w.compass('c-1')); /* 末尾子控件. */
    console.log(w.compass('s5')); /* 索引 5 兄弟控件. */
    console.log(w.compass('s-2')); /* 倒数第 2 兄弟控件. */
    console.log(w.compass('s<1')); /* 相邻左侧兄弟节点. */
    console.log(w.compass('s>1')); /* 相邻右侧兄弟节点. */
    console.log(w.compass('p4c0>1>1>0')); /* 多级访问. */

罗盘参数有以下几类:

- p: parent (父控件)
- c: child (子控件)
- s: sibling (兄弟控件)
- k: clickable (可点击控件)

不同种类的罗盘参数可以重复使用或组合使用.

#### parent (p)#

访问父控件.

如 `w.parent()` 的两种罗盘定位形式:

    w.compass('p'); /* 较为常用. */
    w.compass('p1');

罗盘 `p` 可跟随一个数字, 表示层级跨度:

    /* 二级. */
    w.parent().parent(); /* 原始方式. */
    w.compass('pp');
    w.compass('p2'); /* 较为常用. */

    /* 五级. */
    w.parent().parent().parent().parent().parent(); /* 原始方式. */
    w.compass('ppppp');
    w.compass('p5'); /* 较为常用. */
    w.compass('p4p');
    w.compass('p3p2');
    w.compass('p2p1p2');

罗盘 `p` 每移动一次, 控件的 depth 将减少一级, 当 depth 为 0 时, 后续所有父级访问均返回 null:

    console.log(w.depth()); /* e.g. 23 */
    console.log(w.compass('p5').depth()); /* e.g. 18 */
    console.log(w.compass('p23').depth()); /* e.g. 0 */
    console.log(w.compass('p24')); // null
    console.log(w.compass('p40')); // null

罗盘 `p` 跟随负数时将抛出异常:

    /* e.g. java.lang.IllegalArgumentException: 无效的剩余罗盘参数: -2 */
    console.log(w.compass('p-2'));

`p0` 将返回控件本身:

    console.log(w.compass('p0') === w); // true

#### child (c)#

访问子控件.

如 `w.child(0)` 的罗盘定位形式:

    w.compass('c0');

罗盘 `c` 可跟随一个整数, 表示子控件索引:

    /* 索引 2 子控件 */
    w.child(2);
    w.compass('c2');

    /* 倒数第 2 子控件. */
    w.child(w.childCount() - 2);
    w.compass('c-2');

连续多级子控件访问, 可使用 `cXcYcZ` 或 `cX>Y>Z` 形式:

    w.child(1).child(1).child(0).child(5).child(2).child(3);
    w.compass('c1c1c0c5c2c3');
    w.compass('c1>1>0>5>2>3'); /* 同上. */

#### sibling (s)#

访问兄弟控件.

例如一个控件有 10 个子控件, 这些子控件互为兄弟控件, 它们拥有同一个父控件.
10 个子控件中, 索引为 n (n > 0 且 n < 9) 的子控件有两个相邻兄弟控件节点, 即索引为 n - 1 的左邻兄弟和索引为 n + 1 的右邻兄弟.

    /* 左邻兄弟节点. */
    w.parent().child(w.indexInParent() - 1);
    w.compass('s<1');

    /* 右邻兄弟节点. */
    w.parent().child(w.indexInParent() + 1);
    w.compass('s>1');

    /* 右侧第 2 个兄弟节点. */
    w.parent().child(w.indexInParent() + 2);
    w.compass('s>2');

    /* 索引 5 的兄弟节点. */
    w.parent().child(5);
    w.compass('s5');

    /* 倒数第 2 个兄弟节点. */
    w.parent().child(w.childCount() - 2);
    w.compass('s-2');

#### clickable (k)#

访问可点击控件.

有些控件本身不可点击, 而是包含在一个可点击控件内部:

    let w = contentMatch(/.+/).findOnce();
    console.log(w.clickable()); // false
    console.log(w.parent().clickable()); // true

对于上述情况的控件, 通常执行 "父控件.click()" 都会达到预期, 即虽然点击的是父控件, 但实际效果和点击这个控件本身是一样的.

在某些情况下, 这样的可点击父控件可能需要两级甚至更多级:

    let w = contentMatch(/.+/).findOnce();
    console.log(w.clickable()); // false
    console.log(w.parent().clickable()); // false
    console.log(w.parent().parent().clickable()); // false
    console.log(w.parent().parent().parent().clickable()); // false
    console.log(w.parent().parent().parent().parent().clickable()); // true

上述示例直到 4 级父控件才是可点击的, 对于这种情况通常需要使用循环语句结合 `clickable` 的条件检测:

    let w = contentMatch(/.+/).findOnce();
    let max = 5;
    let temp = w;
    while (max--) {
        if (temp !== null && temp.clickable()) {
            temp.click();
            break;
        }
        temp = temp.parent();
    }

上述示例的 `max` 变量表示最多尝试的层级数, 层级数过小, 可能导致错过真正可点击的父控件, 过大则可能会得到不相关的可点击控件 (这样的控件点击后将出现非预期结果), 通常这个 `max` 建议设置为 2.

将上述示例用控件罗盘表示:

    let w = contentMatch(/.+/).findOnce();
    let temp = w.compass('k5'); /* 5 表示尝试的最大层级数, 通常建议设置为 2. */
    if (temp !== null && temp.clickable()) {
        temp.click();
    }

将上述示例用 拾取选择器 表示:

    pickup(/.+/, 'k5', 'click');

## [m] isCompass#

### isCompass(s)#

`6.2.0` `A11Y`

- s { string } - 罗盘参数
- returns { UiObject | null }

检测罗盘参数是否符合既定格式.

    console.log(UiObject.isCompass('p2c3')); // true
    console.log(UiObject.isCompass('p-2c3')); // true
    console.log(UiObject.isCompass('p2c-3')); // true
    console.log(UiObject.isCompass('hello')); // false

上述示例中的 `p-2c3` 罗盘参数, 在使用时会抛出异常, 但因符合既定格式, 故 `isCompass` 返回 `true`.

## [m] ensureCompass#

### ensureCompass(s)#

`6.2.0` `A11Y`

- s { string } - 罗盘参数
- returns { UiObject | null }

确保罗盘参数符合既定格式, 若不符合则抛出异常.

    UiObject.ensureCompass('p2c3'); /* 无异常. */
    UiObject.ensureCompass('world'); /* 抛出异常. */

## [m] detect#

控件探测.

探测相当于对控件进行一系列组合操作 (罗盘定位, 结果筛选, 参化调用, 回调处理).

部分特性:

- `detect` 已全局化, 支持全局使用.
- `detect` 的首个参数固定为 UiObject 类型.
- compass 是 `detect` 的衍生方法.
- pickup 的内部实现引用了 `detect` 方法.

### detect(w, compass)#

`6.2.0` `Global` `Overload 1/7` `A11Y`

- w { UiObject } - 控件节点
- compass { DetectCompass } - 罗盘参数
- returns { UiObject | null } - 探测后的控件节点

携带 罗盘参数 的控件探测.

相当于 w.compass(compass), 因此 `compass` 是 `detect` 的衍生方法.

### detect(w, result)#

`6.2.0` `Global` `Overload 2/7` `A11Y`

- w { UiObject } - 控件节点
- result { DetectResult } - 探测结果参数
- returns { UiObject | null } - 探测结果

携带 探测结果参数 的控件探测.

### detect(w, compass, result)#

`6.2.0` `Global` `Overload 3/7` `A11Y`

- w { UiObject } - 控件节点
- compass { DetectCompass } - 罗盘参数
- result { DetectResult } - 探测结果参数
- returns { UiObject | null } - 探测结果

携带 罗盘参数 和 探测结果参数 的控件探测.

需特别留意 compass 和 result 的顺序, 两者均为字符串时, 前者会被解析为 `罗盘参数`.

    console.log(w.parent().parent().child(1).child(0).bounds()); /* 潜在的空指针异常. */
    console.log(detect(w, 'p2c1>0', 'bounds')); /* 空指针安全. */

### detect(w, callback)#

`6.2.0` `Global` `Overload 4/7` `A11Y`

- w { UiObject } - 控件节点
- callback { DetectCallback } - 探测回调
- returns { UiObject | null } - 探测回调的结果

携带 探测回调 的控件探测.

    detect(pickup(/^[A-Z][a-z]+ ?\d*$/), (w) => {
        w ? w.click() : console.warn('未找到指定控件');
    });

### detect(w, compass, callback)#

`6.2.0` `Global` `Overload 5/7` `A11Y`

- w { UiObject } - 控件节点
- compass { DetectCompass } - 罗盘参数
- callback { DetectCallback } - 探测回调
- returns { UiObject | null } - 探测回调的结果

携带 罗盘参数 和 探测回调 的控件探测.

    detect(pickup(/^[A-Z][a-z]+ ?\d*$/), 'k2', (w) => {
        w ? w.click() : console.warn('未找到指定控件');
    });

### detect(w, result, callback)#

`6.2.0` `Global` `Overload 6/7` `A11Y`

- w { UiObject } - 控件节点
- result { DetectResult } - 探测结果参数
- callback { DetectCallback } - 探测回调
- returns { UiObject | null } - 探测回调的结果

携带 探测结果参数 和 探测回调 的控件探测.

    detect(pickup(/^[A-Z][a-z]+ ?\d*$/), 'content', (content) => {
        content ? console.log(content) : console.warn('无文本内容或未能定位指定控件');
    });

### detect(w, compass, result, callback)#

`6.2.0` `Global` `Overload 7/7` `A11Y`

- w { UiObject } - 控件节点
- compass { DetectCompass } - 罗盘参数
- result { DetectResult } - 探测结果参数
- callback { DetectCallback } - 探测回调
- returns { UiObject | null } - 探测回调的结果

携带 罗盘参数, 探测结果参数 和 探测回调 的控件探测.

需特别留意 compass 和 result 的顺序, 两者均为字符串时, 前者会被解析为 `罗盘参数`.

    detect(pickup({ clickable: true }), 'p2c1', 'content', (content) => {
        content ? console.log(content) : console.warn('无文本内容或未能定位指定控件');
    });