Element 控件对象
通过 query:get() 或 query:all() 获得的控件对象。
属性
.text
控件的文本内容。
local elem = node.app():id("title"):get()
print(elem.text) -- "商品标题"
.hint
输入框的提示文本(EditText 的 hint)。
print(elem.hint) -- "请输入用户名"
.desc
控件的描述(content-description)。
print(elem.desc) -- "返回按钮"
.type
控件类型(Android 类名,对应 getClassName())。
print(elem.type) -- "android.widget.Button"
print(elem.type) -- "android.widget.TextView"
print(elem.type) -- "android.view.View"
常见类型:
android.widget.Button- 按钮android.widget.TextView- 文本android.widget.EditText- 输入框android.widget.ImageView- 图片android.widget.CheckBox- 复选框android.widget.RecyclerView- 列表
.id
控件 ID(完整资源 ID,对应 getViewIdResourceName())。
print(elem.id) -- "com.example:id/btn_ok"
说明:格式为 包名:id/ID名,可能为空字符串(控件无 ID)
.pkg
控件所属包名。
print(elem.pkg) -- "com.example.app"
.bounds
控件位置和大小(屏幕坐标,基于 getBoundsInScreen())。
local b = elem.bounds
-- 基础属性
print(b.x, b.y) -- 左上角坐标(屏幕坐标系)
print(b.width, b.height) -- 宽高
-- 计算属性
print(b.left, b.top) -- = x, y
print(b.right, b.bottom) -- = x+width, y+height
print(b.centerX, b.centerY) -- 中心点
说明:坐标是相对于屏幕左上角的绝对坐标,可直接用于 node.tap(x, y)
.clickable
是否可点击。
if elem.clickable then
elem:click()
end
.longClickable
是否可长按。
.enabled
是否可用。
.checkable
是否可选中(CheckBox、Switch 等控件)。
.checked
是否已选中(CheckBox、Switch 等)。
.focused
是否获得焦点。
.focusable
是否可聚焦。
.selected
是否被选择。
.editable
是否可编辑(EditText 等输入控件)。
if elem.editable then
elem:input("文本")
end
.visible
是否可见(基于 isVisibleToUser())。
.scrollable
是否可滚动。
if elem.scrollable then
elem:scrollDown()
end
.childCount
子控件数量。
print(elem.childCount) -- 3
.depth
控件在树中的深度。
.index
控件在父控件中的索引(从 0 开始)。
注意:这与 Query 的 index(n) 方法不同:
elem.index- 控件在父控件中的位置,从 0 开始query:index(n)- 从查询结果中取第 n 个,从 1 开始
关系方法
:parent()
获取父控件。
返回值: Element/nil - 根节点的 parent() 返回 nil
local parent = elem:parent()
if parent then
print(parent.type)
end
:children()
获取所有直接子控件。
返回值: table - Element 数组,无子控件时返回空表 {}
-- children() 返回空表,不是 nil,可直接 ipairs
local children = elem:children()
for i, child in ipairs(children) do
print(i, child.text)
end
:child(n)
获取第 n 个子控件。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| n | number | 索引,从 1 开始,负数从末尾计数 |
边界情况:
child(0)- 无效,返回 nil- 正数越界 - 返回 nil
- 负数越界 - 返回 nil
-- 第一个子控件
local first = elem:child(1)
-- 最后一个子控件
local last = elem:child(-1)
-- 第 3 个子控件(如果不足 3 个,返回 nil)
local third = elem:child(3)
:next()
获取下一个兄弟控件。
返回值: Element/nil - 已是最后一个时返回 nil
local nextSibling = elem:next()
:prev()
获取上一个兄弟控件。
返回值: Element/nil - 已是第一个时返回 nil
local prevSibling = elem:prev()
:sibling(n)
获取第 n 个兄弟控件(相对于自身)。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| n | number | 偏移量,正数向后,负数向前 |
边界情况:
sibling(0)- 返回自身- 越界 - 返回 nil
local next2 = elem:sibling(2) -- 后面第 2 个
local prev3 = elem:sibling(-3) -- 前面第 3 个
local self = elem:sibling(0) -- 返回自身
:query()
在此控件内创建新的查询器。
返回值: Query - 以当前控件为根的查询器
说明:
- 返回的 Query 只在当前控件的子树内查找
- 无论当前控件是普通控件还是 WebView,都返回同类型的 Query
-- 在容器内查找
local container = node.app():id("list"):get()
local item = container:query():text("目标项"):get()
-- 在 WebView 内查找
local wv = node.app():type("WebView"):get()
local btn = wv:query():text("提交"):get()
-- 链式调用
local price = node.app():id("product")
:get()
:query():textContains("¥"):get()
动作方法
所有动作方法返回 boolean, string?,第二个值为失败原因。
错误字符串列表
| 错误字符串 | 含义 |
|---|---|
"element is stale" | 控件已失效(界面已变化) |
"action not supported" | 控件不支持此动作 |
"service disconnected" | 无障碍服务断开 |
"element not visible" | 控件不可见(可能被遮挡) |
"element not focusable" | 控件不可聚焦 |
"element not editable" | 控件不可编辑 |
"element not scrollable" | 控件不可滚动 |
"scroll reached end" | 滚动已到达边界 |
:click()
点击控件。
返回值: boolean, string? - 是否成功,失败原因
local ok, err = elem:click()
if not ok then
print("点击失败:", err)
end
:longClick()
长按控件。
返回值: boolean, string?
local ok, err = elem:longClick()
:doubleClick()
双击控件。
返回值: boolean, string?
实现说明: 内部连续执行两次点击,间隔约 100ms
local ok, err = elem:doubleClick()
:input(text)
输入文本(会先清空原有内容)。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| text | string | 要输入的文本(支持中文和 Unicode) |
说明:
- 中文和特殊字符完全支持
- 换行符
\n会被正确处理 - 空字符串等效于
clear()
返回值: boolean, string?
local ok, err = elem:input("hello world")
local ok, err = elem:input("你好世界") -- 中文支持
local ok, err = elem:input("line1\nline2") -- 多行文本
:append(text)
追加文本(不清空原有内容)。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| text | string | 要追加的文本 |
返回值: boolean, string?
local ok, err = elem:append(" 追加内容")
:clear()
清空文本。
适用控件: EditText 等可编辑控件
返回值: boolean, string?
local ok, err = elem:clear()
:focus()
获取焦点。
适用控件: EditText、Button 等可聚焦控件
返回值: boolean, string?
local ok, err = elem:focus()
:blur()
清除焦点(将焦点移至父控件或下一个可聚焦控件)。
返回值: boolean, string?
local ok, err = elem:blur()
:scrollUp() / :scrollDown() / :scrollLeft() / :scrollRight()
方向滚动控件。
适用控件: ScrollView、ListView、RecyclerView、ViewPager 等可滚动控件
返回值: boolean, string?
elem:scrollDown()
elem:scrollUp()
elem:scrollLeft()
elem:scrollRight()
:scrollForward() / :scrollBackward()
向前/向后滚动(AccessibilityService 原生支持)。
说明: Forward/Backward 由系统根据控件方向自动判断滚动方向
返回值: boolean, string?
elem:scrollForward()
elem:scrollBackward()
:scrollIntoView()
滚动父容器使自身可见。
返回值: boolean, string?
失败条件:
- 父容器不可滚动
- 控件已失效
- 无法确定滚动方向
local item = node.app():text("目标项"):get()
if item then
local ok, err = item:scrollIntoView()
if not ok then print("滚动失败:", err) end
end
:select() / :deselect()
选中/取消选中控件。
适用控件: Tab、可选列表项、SegmentedControl 等
返回值: boolean, string?
:expand() / :collapse()
展开/折叠控件。
适用控件: ExpandableListView、Spinner、可折叠面板等
返回值: boolean, string?
:dismiss()
关闭控件(对话框等)。
适用控件: Dialog、BottomSheet、Snackbar、通知等可关闭的控件
返回值: boolean, string?
:copy() / :cut() / :paste()
复制/剪切/粘贴操作。
前置条件:
copy()/cut()- 需要先调用setSelection()选中文本paste()- 系统剪贴板需要有内容
返回值: boolean, string?
-- 复制文本示例
elem:setSelection(0, 10) -- 先选中
elem:copy() -- 再复制
:setSelection(from, to)
设置文本选区。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| from | number | 起始位置(0 开始) |
| to | number | 结束位置(不含) |
边界情况:
from >= to- 清除选区(光标定位到 from)- 越界自动裁剪到文本长度
- 仅对可编辑控件有效
返回值: boolean, string?
local ok = elem:setSelection(0, 5) -- 选中前 5 个字符(索引 0-4)
local ok = elem:setSelection(5, 5) -- 光标定位到第 5 个字符后
实用方法
:refresh()
刷新控件信息(重新从控件树获取)。
返回值: boolean - 刷新是否成功
说明:
- 返回
true- 控件仍然存在,属性已更新 - 返回
false- 控件已不存在(界面已变化)
if elem:refresh() then
print(elem.text) -- 获取最新文本
else
print("控件已失效")
end
:isValid()
检查控件是否仍然有效(不刷新属性)。
返回值: boolean
与 refresh() 的区别:
isValid()- 仅检查引用是否有效,不更新属性,开销小refresh()- 重新获取最新属性,开销较大
if elem:isValid() then
elem:click()
else
-- 控件已失效,需要重新查找
elem = node.app():text("确定"):get()
end
:screenshot()
截取控件区域截图。
返回值: Image/nil - 图像对象,失败返回 nil
说明:
- 返回的 Image 与
screen模块的 Image 类型相同 - 控件失效或不可见时返回 nil
local img = elem:screenshot()
if img then
img:save("/sdcard/btn.png")
end
:dump()
获取控件及其子树的结构信息。
返回值: table - 控件树结构
local tree = elem:dump()
print(json.encode(tree))
:toString() / __tostring
获取控件的可读描述字符串。
返回值: string
local elem = node.app():text("确定"):get()
print(elem:toString()) -- "Button[text=确定, id=btn_ok, bounds=(100,200,300,250)]"
-- 也可以直接 print(自动调用 __tostring)
print(elem)
使用示例
遍历列表
local list = node.app():type("RecyclerView"):get()
if list then
local items = list:children()
for i, item in ipairs(items) do
-- 获取每项的标题和价格
local title = item:query():type("TextView"):index(1):get()
local price = item:query():textContains("¥"):get()
if title and price then
print(title.text, price.text)
end
end
end
关系查询
-- 通过子控件特征定位父容器
local label = node.app():text("商品名称"):get()
local card = label:parent():parent() -- 向上两级
-- 获取同级控件
local price = label:next() -- 下一个兄弟
local image = label:prev() -- 上一个兄弟
-- 在父容器内查找
local btn = card:query():text("购买"):get()
if btn then btn:click() end
等待状态变化
local checkbox = node.app():type("CheckBox"):get()
-- 点击切换状态
checkbox:click()
-- 等待状态变化
checkbox:refresh()
if checkbox.checked then
print("已选中")
end