控件节点行为 (UiObjectActions)
UiObjectActions 是一个 Java 接口, 代表 控件节点 (UiObject) 的行为集合.
该接口有一个抽象方法 performAction 是执行具体的控件节点行为的核心.
诸如 [ click / copy / paste ] 等方法均是对 performAction 的封装, 因此用户也可利用 performAction 实现自定义控件节点行为的封装.
下表列出了部分行为 ID 名称, 及对应已实现封装的方法名称 (星号表示 AutoJs6 新增方法):
| 行为 ID | 封装方法名 | 最低 API 等级 |
|---|---|---|
| ACTION_ACCESSIBILITY_FOCUS | accessibilityFocus | - |
| ACTION_CLEAR_ACCESSIBILITY_FOCUS | clearAccessibilityFocus | - |
| ACTION_CLEAR_FOCUS | clearFocus | - |
| ACTION_CLEAR_SELECTION | clearSelection * | - |
| ACTION_CLICK | click | - |
| ACTION_COLLAPSE | collapse | - |
| ACTION_CONTEXT_CLICK | contextClick | - |
| ACTION_COPY | copy | - |
| ACTION_CUT | cut | - |
| ACTION_DISMISS | dismiss | - |
| ACTION_DRAG_CANCEL | dragCancel * | 32 (12.1) [S_V2] |
| ACTION_DRAG_DROP | dragDrop * | 32 (12.1) [S_V2] |
| ACTION_DRAG_START | dragStart * | 32 (12.1) [S_V2] |
| ACTION_EXPAND | expand | - |
| ACTION_FOCUS | focus | - |
| ACTION_HIDE_TOOLTIP | hideTooltip * | 28 (9) [P] |
| ACTION_IME_ENTER | imeEnter * | 30 (11) [R] |
| ACTION_LONG_CLICK | longClick | - |
| ACTION_MOVE_WINDOW | moveWindow * | 26 (8) [O] |
| ACTION_NEXT_AT_MOVEMENT_GRANULARITY | nextAtMovementGranularity * | - |
| ACTION_NEXT_HTML_ELEMENT | nextHtmlElement * | - |
| ACTION_PAGE_DOWN | pageDown * | 29 (10) [Q] |
| ACTION_PAGE_LEFT | pageLeft * | 29 (10) [Q] |
| ACTION_PAGE_RIGHT | pageRight * | 29 (10) [Q] |
| ACTION_PAGE_UP | pageUp * | 29 (10) [Q] |
| ACTION_PASTE | paste | - |
| ACTION_PRESS_AND_HOLD | pressAndHold * | 30 (11) [R] |
| ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY | previousAtMovementGranularity * | - |
| ACTION_PREVIOUS_HTML_ELEMENT | previousHtmlElement * | - |
| ACTION_SCROLL_BACKWARD | scrollBackward | - |
| ACTION_SCROLL_DOWN | scrollDown | - |
| ACTION_SCROLL_FORWARD | scrollForward | - |
| ACTION_SCROLL_LEFT | scrollLeft | - |
| ACTION_SCROLL_RIGHT | scrollRight | - |
| ACTION_SCROLL_TO_POSITION | scrollTo | - |
| ACTION_SCROLL_UP | scrollUp | - |
| ACTION_SELECT | select | - |
| ACTION_SET_PROGRESS | setProgress | - |
| ACTION_SET_SELECTION | setSelection | - |
| ACTION_SET_TEXT | setText | - |
| ACTION_SHOW_ON_SCREEN | show | - |
| ACTION_SHOW_TEXT_SUGGESTIONS | showTextSuggestions * | 33 (13) [TIRAMISU] |
| ACTION_SHOW_TOOLTIP | showTooltip * | 28 (9) [P] |
若当前设备不满足列表中最低 API 等级要求, 使用对应方法时不会抛出异常, 会静默返回 false:
/*
例如 ACTION_IME_ENTER 要求设备运行条件不低于 Android API 30 (11) [R].
在 API < 30 的设备上一定返回 false 且 IME ENTER 无效果 (但不会抛出异常).
*/
console.log(pickup({
focusable: true,
contentMatch: '.+',
}, 'imeEnter'));上表中所有已封装的控件行为对应的方法 名称 均已全局化, 有关全局化方法的使用方式及方法的绑定源信息, 可参阅 全局行为重定向 小节.
参阅: Android Docs
UiObjectActions
[m!] performAction
用于执行指定的控件行为.
是一个无默认实现的抽象方法.
performAction(action, ...arguments)
A11Y
- action { number } - 行为的唯一标志符 (Action ID)
- arguments { ...ActionArgument[] } - 行为参数, 用于给行为传递参数
- returns { boolean } - 是否行为已执行且执行过程中无异常
实现此方法的类有:
源代码摘要:
- UiSelector
/* Updated as of Nov 2, 2022. */
override fun performAction(action: Int, vararg arguments: ActionArgument): Boolean {
return untilFind().performAction(action, *arguments)
}- UiObject
/* Updated as of Nov 2, 2022. */
override fun performAction(action: Int, vararg arguments: ActionArgument): Boolean {
return performAction(action, Bundle().apply { arguments.forEach { it.putIn(this) } })
}
override fun performAction(action: Int, bundle: Bundle): Boolean = try {
when (bundle.isEmpty) {
true -> super.performAction(action)
else -> super.performAction(action, bundle)
}
} catch (e: IllegalStateException) {
false
}- UiObjectCollection
/* Updated as of Nov 2, 2022. */
override fun performAction(action: Int, vararg arguments: ActionArgument): Boolean {
var success = true
nodes.filterNotNull().forEach { node ->
when (arguments.isEmpty()) {
true -> node.performAction(action)
else -> node.performAction(action, *arguments)
}.also { success = success and it }
}
return success
}由此可见, UiSelector 与 UiObjectCollection 最终都调用了 UiObject 的 performAction 方法, 而 UiObject 的 performAction 则调用了 Android 系统的 AccessibilityNodeInfoCompat#performAction 方法
UiObjectCollection 相当于对控件集合中的每一个控件执行 UiObject#performAction 方法.UiSelector 相当于先执行 untilFind 找到当前窗口中所有控件, 将其作为集合执行 UiObjectCollection#performAction 方法.
因全局的 untilFind() 是 "无条件" 筛选, 会把窗口中所有控件 (往往会有几十甚至成百上千个控件) 全部加入集合中, 此时执行任何 行为 (Action), 都相当于集合中所有控件执行一遍上述行为, 这样的操作往往是无意义的, 很可能造成非预期结果甚至不可控的操作, 因此不建议使用 UiSelector 提供的 行为 (Action) 方法.
下面列举一个 UiSelector 提供的行为, 再次强调不建议使用:
/* ACTION_SET_TEXT 行为 */
/* 对当前窗口中所有支持设置文本的控件, 将内容设置为 "hello". */
selector().setText("hello");
/* UiSelector 几乎所有方法均已全局化, setText 位列其中. */
setText("hello"); /* 效果同上. */如有上述示例的需求 (对控件设置文本内容), 而且是针对多个控件同时设置, 建议使用选择器定位指定的控件集合, 再统一执行 行为 (Action):
/* 先筛选集合. */
let nodes = pickup({
focusable: true,
textMatch: "name",
boundInside: [ cX(0.2), cYx(0.04), cX(0.8), cY(0.92) ],
}, '[w]');
/* 再执行行为. */
nodes.forEach(w => w.setText("hello"));如需对控件执行自定义行为, 可通过 UiObject#performAction 实现:
/* 对控件执行 ACTION_IME_ENTER 行为. */
let { AccessibilityActionCompat } = androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
let w = focusable().contentMatch(/name/).findOnce();
w.performAction(AccessibilityActionCompat.ACTION_IME_ENTER.id);有些 行为 (Action) 需要指定参数, 此时可借助 ActionArgument 接口传入参数:
/* 对控件执行 ACTION_SET_TEXT 及 ACTION_SET_SELECTION 行为. */
let { AccessibilityNodeInfoCompat } = androidx.core.view.accessibility
let { AccessibilityActionCompat } = AccessibilityNodeInfoCompat;
let { ActionArgument } = org.autojs.autojs.core.automator;
let w = focusable().contentMatch(/name/).findOnce();
/* ACTION_SET_TEXT 需要一个 ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE "行为参数". */
w.performAction(
AccessibilityActionCompat.ACTION_SET_TEXT.id,
ActionArgument.CharSequenceActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "hello"),
);
/* ACTION_SET_SELECTION 需要两个 "行为参数", */
/* ACTION_ARGUMENT_SELECTION_START_INT 及 ACTION_ARGUMENT_SELECTION_END_INT. */
w.performAction(
AccessibilityActionCompat.ACTION_SET_SELECTION.id,
ActionArgument.IntActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT, 1),
ActionArgument.IntActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT, 4),
);UiObject 拥有另一个实例方法 performAction(action, bundle), 因此上述示例也可改写为:
let arguments = new android.os.Bundle();
arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT, 1);
arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT, 4);
w.performAction(AccessibilityActionCompat.ACTION_SET_SELECTION.id, arguments);如需判断控件是否有某个或某些 Action, 可使用 UiObject#hasAction:
console.log(w.hasAction("ACTION_CLICK"));
console.log(w.hasAction("CLICK")); /* 前缀 "ACTION_" 可省略. */
/* 检查是否同时拥有多个 Action. */
console.log(w.hasAction("CLICK", "IME_ENTER", "SCROLL_UP"));如需使用 Action 选择器筛选控件, 可使用 UiSelector#action:
console.log(action("ACTION_CLICK").findOnce());
console.log(action("CLICK").findOnce()); /* 前缀 "ACTION_" 可省略. */
/* 筛选多个 Action. */
console.log(action("CLICK", "IME_ENTER", "SCROLL_UP").findOnce());[m=] click
click()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 点击 ] 行为.
检查一个控件节点是否可点击:
console.log(w.clickable());
console.log(w.isClickable()); /* 同上. */以下情况可能导致 w.click() 返回 false:
- 控件不可点击 (
w.clickable()为false) - 页面无法响应点击事件
有时会出现虽然 w 不可点击但 w.parent() 或 w.parent().parent() 等父级控件可点击的情况:
function tryClick(w) {
let max = 3;
let tmp = w;
while (max--) {
tmp = tmp.parent();
if (tmp.isClickable()) {
return tmp.click();
}
}
return false;
}
console.log(tryClick(w));
/* 上述过程可使用 pickup 简化. */
console.log(pickup(w, 'k3', 'click'));使用控件的 click 方法主要优缺点 (相较于坐标模拟点击):
- [优] 速度较快
- [优] 适用于位置不断变化的控件
- [优] 适用于不在窗口可视化范围内的控件
- [优] 适用于上层被其他控件覆盖或遮挡的控件
- [劣] 部分控件难以通过选择器精确定位
- [劣] 部分控件执行
click行为后无响应 - [劣] 无法完全适应控件属性或层级关系改变的情况
鉴于上述优劣项, 控件的 click 方法通常与 [ global.click (automator.click) / UiObject#clickByBounds ] 等方法配合使用.
[m=] longClick
longClick()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 长按 ] 行为.
检查一个控件节点是否可长按:
console.log(w.longClickable());
console.log(w.isLongClickable()); /* 同上. */以下情况可能导致 w.longClick() 返回 false:
- 控件不可长按 (
w.longClickable()为false) - 页面无法响应长按事件
[m=] accessibilityFocus
accessibilityFocus()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 获取无障碍焦点 ] 行为.
只有在当前设备启用了无障碍软件 (如 TalkBack) 才能正常使用 accessibilityFocus().
以 TalkBack 为例, 启用后, 当前窗口中获取无障碍焦点的控件将被绿色方框标记其边界, 此时按下键盘回车键或无障碍设备 (如 D-pad) 的确定键 (取决于不同设备), 即可激活此控件.
/* 获得无障碍焦点. */
console.log(pickup(idEndsWith('fab'), 'accessibilityFocus')); /* boolean 类型结果. */
/* 检查是否已获得无障碍焦点. */
console.log(pickup(idEndsWith('fab'), 'accessibilityFocused')); /* boolean 类型结果. */如需清除焦点, 可使用 clearAccessibilityFocus 方法.
[m=] clearAccessibilityFocus
clearAccessibilityFocus()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 清除无障碍焦点 ] 行为.
只有在当前设备启用了无障碍软件 (如 TalkBack) 才能正常使用 clearAccessibilityFocus().
/* 清除无障碍焦点. */
console.log(pickup(idEndsWith('fab'), 'clearAccessibilityFocus')); /* boolean 类型结果. */[m=] focus
focus()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 获取焦点 ] 行为.
在当前设备连接外置键盘等输入设备时, 按下 TAB 或 方向键可在控件之间 "切换", 这些控件都是 focusable (可被聚焦) 的.
/* 查看控件是否可被聚焦. */
console.log(w.focusable());
console.log(w.isFocusable()); /* 同上. */当控件被聚焦 (即获取焦点) 后, 可使用输入设备的 ENTER 或 OK 等表示确认的按键激活此控件.
如果此控件支持文本输入 (例如常见的 EditText 类型控件), 在被聚焦后, 将出现输入光标, 且可能会弹出软键盘用于用户输入内容.
/* 打印当前窗口支持聚焦的控件文本内容数组. */
console.log(pickup({ focusable: true }, 'txt[]'));
/* 按文本内容筛选一个控件并使其获得焦点. */
pickup([ { focusable: true }, /search/ ], 'focus');如需清除焦点, 可使用 clearFocus 方法.
[m=] clearFocus
clearFocus()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 清除焦点 ] 行为.
对一个可被聚焦的控件, 如果它没有获得焦点, 调用 clearFocus 方法时将返回 false.
/* w 可被聚焦, 但当前未获得焦点. */
console.log(w.focusable()); // true
console.log(w.isFocused()); // false
/* isFocused 返回 false, 因此 clearFocus 也返回 false. */
console.log(w.clearFocus()); // false[m=] dragStart
dragStart()
6.2.0 A11Y API>=32
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 拖放开始 ] 行为.
此操作将初始化系统内部的拖放 (Drag & Drop) 功能.
支持拖放的内容将在拖放行为开始前完成准备.
[m=] dragDrop
dragDrop()
6.2.0 A11Y API>=32
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 拖放放下 ] 行为.
此操作针对于已开始 ACTION_DRAG_START 行为的拖放目标.
[m=] dragCancel
dragCancel()
6.2.0 A11Y API>=32
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 拖放取消 ] 行为.
此操作针对于已开始 ACTION_DRAG_START 行为的拖放目标.
[m=] imeEnter
imeEnter()
6.2.0 A11Y API>=30
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 输入法 ENTER 键 ] 行为.
此操作通常只对获得焦点且可编辑的控件有效.
通常 imeEnter 用来模拟回车键在文本控件实现换行功能.
另外也可以模拟某些表示确认的操作, 如 [ 搜索 / 发送 / 下一步 / 立即前往 / 开始执行 ] 等.
/* 模拟回车键. */
console.log(pickup({
className: 'EditText',
focused: true,
}, 'imeEnter')); /* e.g. true */[m=] moveWindow
moveWindow(x, y)
6.2.0 A11Y API>=26
控件节点执行 [ 移动窗口到新位置 ] 行为.
[m=] nextAtMovementGranularity
nextAtMovementGranularity(granularity, isExtendSelection)
6.2.0 A11Y
- granularity { number } - 粒度
- isExtendSelection { boolean } - 是否扩展选则文本
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 按粒度移至下一位置 ] 行为.
按指定粒度移动光标到下一个文本实体位置, 例如移动到下一个单词, 下一行, 下一个段落等.
const AccessibilityNodeInfo = android.view.accessibility.AccessibilityNodeInfo;
let w = pickup([ /.+/, { className: 'EditText' } ]);
/* 按 WORD (单词) 粒度移动. */
/* 除 WORD 外, 还支持 CHARACTER (字符), LINE (行), PARAGRAPH (段落), PAGE (页) 等粒度. */
w.nextAtMovementGranularity(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD, false);[m=] nextHtmlElement
nextHtmlElement(element)
6.2.0 A11Y
控件节点执行 [ 按元素移至下一位置 ] 行为.
按指定元素名称移动焦点至下一元素位置, 例如移动到下一个按钮, 下一个列表, 下一个输入框等.
console.log(w.nextHtmlElement("BUTTON"));[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 } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 按住 ] 行为.
按住即按下并保持, 与 ACTION_LONG_CLICK (长按) 不同.
如果控件的单一行为响应是为 "长按" 设计的, 则应该使用封装的 longClick 方法, 而非 pressAndHold 方法.
只有控件存在对 "按住" 行为的响应, 才会使 pressAndHold 有效.
通常控件不会同时存在上述两种行为的响应.
[m=] previousAtMovementGranularity
previousAtMovementGranularity(granularity, isExtendSelection)
6.2.0 A11Y
- granularity { number } - 粒度
- isExtendSelection { boolean } - 是否扩展选则文本
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 按粒度移至上一位置 ] 行为.
按指定粒度移动光标到上一个文本实体位置, 例如移动到上一个单词, 上一行, 上一个段落等.
const AccessibilityNodeInfo = android.view.accessibility.AccessibilityNodeInfo;
let w = pickup([ /.+/, { className: 'EditText' } ]);
/* 按 WORD (单词) 粒度移动. */
/* 除 WORD 外, 还支持 CHARACTER (字符), LINE (行), PARAGRAPH (段落), PAGE (页) 等粒度. */
w.previousAtMovementGranularity(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD, false);[m=] previousHtmlElement
previousHtmlElement(element)
6.2.0 A11Y
控件节点执行 [ 按元素移至上一位置 ] 行为.
按指定元素名称移动焦点至上一元素位置, 例如移动到上一个按钮, 上一个列表, 上一个输入框等.
console.log(w.previousHtmlElement("BUTTON"));[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 } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 显示在视窗内 ] 行为.
此操作使控件的所有边界全部出现在视窗内部.
如有需要, 页面会发生滚动.
/* "关于应用与开发者" 按钮部分 (或全部) 位于视窗外部. */
let w = pickup("关于应用与开发者");
if (w !== null) {
/* 控件将随着页面滚动到视窗内部. */
w.show();
}[m=] dismiss
dismiss()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 消隐 ] 行为.
检查一个控件节点是否可消隐:
console.log(w.dismissable());
console.log(w.isDismissable()); /* 同上. */[m=] copy
copy()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 复制文本 ] 行为.
此操作将控件的已选中文本内容复制到剪贴板.
[m=] cut
cut()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 剪切文本 ] 行为.
此操作将控件的已选中文本内容剪切并置于剪贴板.
[m=] paste
paste()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 粘贴文本 ] 行为.
此操作将剪贴板的文本内容粘贴到控件的可编辑文本区域.
需额外留意, 自 Android API 29 (10) [Q] 起, 剪贴板数据的访问将受到限制.
详情参阅 getClip.
[m=] select
select()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 选中 ] 行为.
此操作将选中当前控件.
检查一个控件节点是否已被选中:
console.log(w.selected());
console.log(w.isSelected()); /* 同上. */[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
控件节点执行 [ 将指定位置滚动至视窗内 ] 行为.
此操作将集合中指定位置 (以 "行" 和 "列" 标记) 滚动至视窗内.
scrollable().find().some((w) => {
let info = w.getCollectionInfo();
if (info !== null) {
console.log(info.getRowCount()); /* e.g. 17 */
console.log(info.getColumnCount()); /* e.g. 2 */
let randRow = Mathx.randInt(info.getRowCount() - 1);
let randColumn = Mathx.randInt(info.getColumnCount() - 1);
console.log(`${randRow},${randColumn}`); /* e.g. 10,1 */
console.log(w.scrollTo(randRow, randColumn)); /* e.g. false */
return /* @some */ true;
}
});[m=] contextClick
contextClick()
A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 上下文点击 ] 行为.
此操作通常会弹出一个上下文菜单, 类似鼠标右键菜单.
注: 在 Microsoft Windows 操作系统中, 单击鼠标右键 (或按下键盘的菜单键) 即类似控件的 Context Click (上下文点击) 行为, 弹出的右键菜单又称为 Context Menu (上下文菜单).
[m=] setText
setText(text)
A11Y
控件节点执行 [ 设置文本 ] 行为.
此操作将使用新文本替换原有文本, 并将光标置于文本末尾.
let w = pickup({ className: 'EditText' });
/* 设置文本为 "hello". */
w.setText("hello");
/* 清空文本. */
w.setText("");[m=] setSelection
setSelection(start, end)
A11Y
控件节点执行 [ 选择文本 ] 行为.
此操作将按指定范围选中控件的文本内容.
let w = pickup({ className: 'EditText' });
/* 选中 2 - 3 的 1 个文本, 起始光标停留在 2 位置, 末尾光标停留在 3 位置. */
w.setSelection(2, 3);
/* 无任何效果, 光标不发生变化. */
w.setSelection(2, 0);
w.setSelection(2, -5);
/* 抛出异常. */
w.setSelection(NaN, 0);
w.setSelection(Infinity, 0);
/* 选中 0 个文本, 此时起始和末尾两个光标重合. */
w.setSelection(2, 2);[m=] clearSelection
clearSelection()
6.2.0 A11Y
- returns { boolean } - 是否行为已执行且执行过程中无异常
控件节点执行 [ 取消选择文本 ] 行为.
[m=] setProgress
setProgress(progress)
A11Y
控件节点执行 [ 设置进度值 ] 行为.
pickup({ action: ['SET_PROGRESS'] }, '[]').some((w) => {
const info = w.getRangeInfo();
if (info !== null) {
console.log(w.getMin(), w.getMax());
let randProgress = Mathx.randInt(w.getMin(), w.getMax());
console.log(randProgress);
console.log(w.setProgress(randProgress));
}
});[I] ActionArgument
控件的行为参数接口.
主要用于自定义控件行为的 performAction 抽象方法内.
[C] IntActionArgument
ActionArgument 的具体类.
用于传递 Int 类型的行为参数.
[c] (name, value)
- name { string } - 行为名称
- value { number } - 行为参数值
- returns { ActionArgument }
构造一个 Int 类型的行为参数.
/* 模拟 scrollTo 封装方法. */
function scrollTo(x, y) {
return w.performAction(
AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION.id,
ActionArgument.IntActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT, x),
ActionArgument.IntActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT, y),
);
}[C] BooleanActionArgument
ActionArgument 的具体类.
用于传递 Boolean 类型的行为参数.
[c] (name, value)
- name { string } - 行为名称
- value { boolean } - 行为参数值
- returns { ActionArgument }
构造一个 Boolean 类型的行为参数.
/* 模拟 nextAtMovementGranularity 封装方法. */
function nextAtMovementGranularity(granularity, isExtendSelection) {
return w.performAction(
AccessibilityActionCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.id,
ActionArgument.IntActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, granularity),
ActionArgument.BooleanActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, isExtendSelection),
);
}[C] CharSequenceActionArgument
ActionArgument 的具体类.
用于传递 CharSequence 类型的行为参数.
[c] (name, value)
- name { string } - 行为名称
- value { string } - 行为参数值
- returns { ActionArgument }
构造一个 CharSequence 类型的行为参数.
/* 模拟 setText 封装方法. */
function setText(text) {
return w.performAction(
AccessibilityActionCompat.ACTION_SET_TEXT.id,
ActionArgument.IntActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text),
);
}[C] StringActionArgument
ActionArgument 的具体类.
用于传递 String 类型的行为参数.
[c] (name, value)
- name { string } - 行为名称
- value { string } - 行为参数值
- returns { ActionArgument }
构造一个 String 类型的行为参数.
/* 模拟 nextHtmlElement 封装方法. */
function nextHtmlElement(element) {
return w.performAction(
AccessibilityActionCompat.ACTION_NEXT_HTML_ELEMENT.id,
ActionArgument.StringActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING, element),
);
}[C] FloatActionArgument
ActionArgument 的具体类.
用于传递 Float 类型的行为参数.
[c] (name, value)
- name { string } - 行为名称
- value { number } - 行为参数值
- returns { ActionArgument }
构造一个 Float 类型的行为参数.
/* 模拟 setProgress 封装方法. */
function nextHtmlElement(progress) {
return w.performAction(
AccessibilityActionCompat.ACTION_SET_PROGRESS.id,
ActionArgument.FloatActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE, progress),
);
}全局行为重定向
本章节所有控件行为对应的方法 名称 均已全局化, 即支持 [ click() / paste() / scrollDown() / show() ] 等全局直接调用的方式来使用.
这些方法多数是 UiSelector 实例方法的直接绑定, 但有部分方法被 SimpleActionAutomator 覆盖.
下表列出了控件行为方法对应的绑定源.
其中 AUTO 代表 SimpleActionAutomator, SEL 代表 UiSelector.
| Global Actions | AUTO | SEL |
|---|---|---|
| accessibilityFocus | √ | |
| clearAccessibilityFocus | √ | |
| clearFocus | √ | |
| clearSelection | √ | |
| click | √ | |
| collapse | √ | |
| contextClick | √ | |
| copy | √ | |
| cut | √ | |
| dismiss | √ | |
| dragCancel | √ | |
| dragDrop | √ | |
| dragStart | √ | |
| expand | √ | |
| focus | √ | |
| hideTooltip | √ | |
| imeEnter | √ | |
| longClick | √ | |
| moveWindow | √ | |
| nextAtMovementGranularity | √ | |
| nextHtmlElement | √ | |
| pageDown | √ | |
| pageLeft | √ | |
| pageRight | √ | |
| pageUp | √ | |
| paste | √ | |
| pressAndHold | √ | |
| previousAtMovementGranularity | √ | |
| previousHtmlElement | √ | |
| scrollBackward | √ | |
| scrollDown | √ | |
| scrollForward | √ | |
| scrollLeft | √ | |
| scrollRight | √ | |
| scrollTo | √ | |
| scrollUp | √ | |
| select | √ | |
| setProgress | √ | |
| setSelection | √ | |
| setText | √ | |
| show | √ | |
| showTextSuggestions | √ | |
| showTooltip | √ |
截至目前 (2022/11), 只有 [ click, longClick, scrollDown, scrollUp, setText ] 全局方法属于 SimpleActionAutomator.
copy(); /* 相当于 selector().copy(). */
paste(); /* 相当于 selector().paste(). */
clearFocus(); /* 相当于 selector().clearFocus(). */
imeEnter(); /* 相当于 selector().imeEnter(). */
click(1, 2); /* 相当于 automator.click(1, 2). */
longClick(1, 2); /* 相当于 automator.longClick(1, 2). */
setText("hello"); /* 相当于 automator.setText("hello"). */
scrollUp(); /* 相当于 automator.scrollUp(). */
scrollDown(); /* 相当于 automator.scrollDown(). */通过 performAction 小节可知, UiSelector 的控件行为方法实际是对当前窗口中所有控件全部执行一次 Action, 因此几乎所有 UiSelector 的控件行为方法均不建议使用.
全局方法 paste 是使用率相对较高的控件行为, 且效果往往与预期相符.
有关全局方法 paste 的执行过程及原理分析可参阅 UiSelector#paste 小节.
