选择器进阶
## selector()
返回 {UiSelector}
创建一个新的选择器。但一般情况不需要使用该函数,因为可以直接用相应条件的语句创建选择器。
由于历史遗留原因,本不应该这样设计(不应该让id(), text()等作为全局函数,而是应该用By.id(), By.text()),但为了后向兼容性只能保留这个设计。
这样的API设计会污染全局变量,后续可能会支持"去掉这些全局函数而使用By.*"的选项。
## UiSelector.text(str)
| 参数 |类型 |描述 |
|-|-|-|
|str|string |控件文本|
| 返回值类型|描述 |
|-|-|-|
|UiSelector|返回选择器自身以便链式调用|
为当前选择器附加控件"text等于字符串str"的筛选条件。
控件的text(文本)属性是文本控件上的显示的文字,例如微信左上角的"微信"文本。
## UiSelector.textContains(str)
| 参数 |类型 |描述 |
|-|-|-|
|str|string |要包含的字符串|
为当前选择器附加控件"text需要包含字符串str"的筛选条件。
这是一个比较有用的条件,例如QQ动态页和微博发现页上方的"大家都在搜...."的控件可以用textContains("大家都在搜").findOne()来获取。
## UiSelector.textStartsWith(prefix)
| 参数 |类型 |描述 |
|-|-|-|
|prefix |string |前缀|
为当前选择器附加控件"text需要以prefix开头"的筛选条件。
这也是一个比较有用的条件,例如要找出Auto.js脚本列表中名称以"QQ"开头的脚本的代码为textStartsWith("QQ").find()。
## UiSelector.textEndsWith(suffix)
| 参数 |类型 |描述 |
|-|-|-|
|suffix |string |后缀|
为当前选择器附加控件"text需要以suffix结束"的筛选条件。
## UiSelector.textMatches(reg)
| 参数 |类型 |描述 |
|-|-|-|
|reg |string |{Regex}要满足的正则表达式|
为当前选择器附加控件"text需要满足正则表达式reg"的条件。
有关正则表达式,可以查看正则表达式 - 菜鸟教程。
需要注意的是,如果正则表达式是字符串,则需要使用\\来表达\(也即Java正则表达式的形式),例如textMatches("\\d+")匹配多位数字;但如果使用JavaScript语法的正则表达式则不需要,例如textMatches(/\d+/)。但如果使用字符串的正则表达式则该字符串不能以"/"同时以"/"结束,也即不能写诸如textMatches("/\\d+/")的表达式,否则会被开头的"/"和结尾的"/"会被忽略。
## UiSelector.desc(str)
| 参数 |类型 |描述 |
|-|-|-|
|reg |string |控件文本|
| 返回值|描述 |
|-|-|-|
|UiSelector |返回选择器自身以便链式调用|
为当前选择器附加控件"desc等于字符串str"的筛选条件。
控件的desc(描述,全称为Content-Description)属性是对一个控件的描述,例如网易云音乐右上角的放大镜图标的描述为搜索。要查看一个控件的描述,同样地可以借助悬浮窗查看。
desc属性同样是定位控件的利器。
## UiSelector.descContains(str)
| 参数 |类型 |描述 |
|-|-|-|
|reg |string |要包含的字符串|
为当前选择器附加控件"desc需要包含字符串str"的筛选条件。
## UiSelector.descStartsWith(prefix)
| 参数 |类型 |描述 |
|-|-|-|
|prefix|string |前缀|
为当前选择器附加控件"desc需要以prefix开头"的筛选条件。
## UiSelector.descEndsWith(suffix)
| 参数 |类型 |描述 |
|-|-|-|
|suffix |string |后缀|
为当前选择器附加控件"desc需要以suffix结束"的筛选条件。
## UiSelector.descMatches(reg)
| 参数 |类型 |描述 |
|-|-|-|
|reg |string |{Regex} 要满足的正则表达式|
为当前选择器附加控件"desc需要满足正则表达式reg"的条件。
有关正则表达式,可以查看正则表达式 - 菜鸟教程。
>d需要注意的是,如果正则表达式是字符串,则需要使用\\来表达\(也即Java正则表达式的形式),例如textMatches("\\d+")匹配多位数字;但如果使用JavaScript语法的正则表达式则不需要,例如textMatches(/\d+/)。但如果使用字符串的正则表达式则该字符串不能以"/"同时以"/"结束,也即不能写诸如textMatches("/\\d+/")的表达式,否则会被开头的"/"和结尾的"/"会被忽略。
## UiSelector.id(resId)
| 参数 |类型 |描述 |
|-|-|-|
|resId |string |控件的id|
>s以"包名:id/"开头,例如"com.tencent.mm:id/send_btn"。也可以不指定包
名,这时会以当前正在运行的应用的包名来补全id。例如id("send_btn"),在QQ界面想当于id("com.tencent.mobileqq:id/send_btn")。
为当前选择器附加"id等于resId"的筛选条件。
微信运动点赞为例子:
```language
object =id("bjb").findonce();
if (object !=null){
object.click();//点击元素
}els{
///自己处理吧
log(“没找到”)
}
```
约baobaoapp寻找性别例子:
```language
let object = id(“v_sex_age”).findonce();
if (object !=null){
object.click();
}else{
///处理
log(“没找到”)
}
}
```
>i控件的id属性通常是可以用来确定控件的唯一标识,如果一个控件有id,那么使用id来找到他是最好的方法。要查看屏幕上的控件的id,可以开启悬浮窗并使用界面工具,点击相应控件即可查看。若查看到的控件id为null, 表示该控件没有id。另外,在列表中会出现多个控件的id相同的情况。例如微信的联系人列表,每个头像的id都是一样的。此时不能用id来唯一确定控件。
在QQ界面经常会出现多个id为"name"的控件,在微信上则每个版本的id都会变化。对于这些软件而言比较难用id定位控件
## UiSelector.idContains(str)
| 参数 |类型 |描述 |
|-|-|-|
|str |string |id要包含的字符串|
为当前选择器附加控件"id包含字符串str"的筛选条件。比较少用。
## UiSelector.idStartsWith(prefix)
| 参数 |类型 |描述 |
|-|-|-|
|prefix|string |id前缀|
为当前选择器附加"id需要以prefix开头"的筛选条件。比较少用。
## UiSelector.idEndsWith(suffix)
| 参数 |类型 |描述 |
|-|-|-|
|suffix |string |id后缀|
为当前选择器附加"id需要以suffix结束"的筛选条件。比较少用。
## UiSelector.idMatches(reg)
| 参数 |类型 |描述 |
|-|-|-|
|reg |Regex| {string} id要满足的正则表达式|
附加id需要满足正则表达式。
>d需要注意的是,如果正则表达式是字符串,则需要使用\\来表达\(也即Java正则表达式的形式),例如textMatches("\\d+")匹配多位数字;但如果使用JavaScript语法的正则表达式则不需要,例如textMatches(/\d+/)。但如果使用字符串的正则表达式则该字符串不能以"/"同时以"/"结束,也即不能写诸如textMatches("/\\d+/")的表达式,否则会被开头的"/"和结尾的"/"会被忽略。
```language
idMatches("[a-zA-Z]+")
```
## UiSelector.className(str)
| 参数 |类型 |描述 |
|-|-|-|
|reg |string| 控件文本|
| 返回值类型|描述 |
|-|-|-|
|UiSelector | 返回选择器自身以便链式调用|
为当前选择器附加控件"className等于字符串str"的筛选条件。
控件的className(类名)表示一个控件的类别,例如文本控件的类名为android.widget.TextView。
如果一个控件的类名以"android.widget."开头,则可以省略这部分,例如文本控件可以直接用className("TextView")的选择器。
|常见控件的类名 |备注 |
|-|-|
|android.widget.TextView |文本控件|
|android.widget.ImageView |图片控件|
|android.widget.Button |按钮控件|
|android.widget.EditText |输入框控件|
|android.widget.AbsListView |列表控件|
|android.widget.LinearLayout |线性布局|
|android.widget.FrameLayout |帧布局|
|android.widget.RelativeLayout |相对布局|
|android.widget.RelativeLayout |相对布局|
|android.support.v7.widget.RecyclerView |通常也是列表控件|
## UiSelector.classNameContains(str)
|要包含的字符串|
|-|-|-|
|str {string}|
为当前选择器附加控件"className需要包含字符串str"的筛选条件。
## UiSelector.classNameStartsWith(prefix)
|前缀|
|-|-|-|
|prefix {string}|
为当前选择器附加控件"className需要以prefix开头"的筛选条件。
## UiSelector.classNameEndsWith(suffix)
|后缀|
|-|-|-|
|suffix {string}|
为当前选择器附加控件"className需要以suffix结束"的筛选条件。
## UiSelector.classNameMatches(reg)
|要满足的正则表达式。|
|-|-|-|
|reg {string} , {Regex}|
为当前选择器附加控件"className需要满足正则表达式reg"的条件。
有关正则表达式,可以查看正则表达式 - 菜鸟教程。
>s需要注意的是,如果正则表达式是字符串,则需要使用\\来表达\(也即Java正则表达式的形式),例如textMatches("\\d+")匹配多位数字;但如果使用JavaScript语法的正则表达式则不需要,例如textMatches(/\d+/)。但如果使用字符串的正则表达式则该字符串不能以"/"同时以"/"结束,也即不能写诸如textMatches("/\\d+/")的表达式,否则会被开头的"/"和结尾的"/"会被忽略。
## UiSelector.packageName(str)
|str {string}|控件文本|
|-|-|-|
|返回 {UiSelector}|返回选择器自身以便链式调用|
为当前选择器附加控件"packageName等于字符串str"的筛选条件。
控件的packageName表示控件所属界面的应用包名。例如微信的包名为"com.tencent.mm", 那么微信界面的控件的packageName为"com.tencent.mm"。
**要查看一个应用的包名,可以用函数app.getPackageName()获取,例如toast(app.getPackageName("微信"))。**
## UiSelector.packageNameContains(str)
|要包含的字符串|
|-|-|-|
|str {string}|
为当前选择器附加控件"packageName需要包含字符串str"的筛选条件。
## UiSelector.packageNameStartsWith(prefix)
|前缀|
|-|-|-|
|prefix {string}|
为当前选择器附加控件"packageName需要以prefix开头"的筛选条件。
## UiSelector.packageNameEndsWith(suffix)
|前缀|
|-|-|-|
|suffix {string}|
为当前选择器附加控件"packageName需要以suffix结束"的筛选条件。
## UiSelector.packageNameMatches(reg)
reg {string} | {Regex} 要满足的正则表达式。
|{Regex}要满足的正则表达式。|
|-|-|-|
|reg {string}|
为当前选择器附加控件"packageName需要满足正则表达式reg"的条件。
有关正则表达式,可以查看正则表达式 - 菜鸟教程。
## UiSelector.bounds(left, top, right, buttom)
|left {number}|控件左边缘与屏幕左边的距离|
|-|-|-|
|top {number}|控件上边缘与屏幕上边的距离|
|right {number}|控件右边缘与屏幕左边的距离|
|bottom {number} |控件下边缘与屏幕上边的距离|
一个控件的bounds属性为这个控件在屏幕上显示的范围。我们可以用这个范围来定位这个控件。尽管用这个方法定位控件对于静态页面十分准确,却无法兼容不同分辨率的设备;同时对于列表页面等动态页面无法达到效果,因此使用不推荐该选择器。
>d注意参数的这四个数字不能随意填写,必须精确的填写控件的四个边界才能找到该控件。例如,要点击QQ主界面的右上角加号,我们用布局分析查看该控件的属性,如下图:
>s可以看到bounds属性为(951, 67, 1080, 196),此时使用代码bounds(951, 67, 1080, 196).clickable().click()即可点击该控件。
## UiSelector.boundsInside(left, top, right, buttom)
left {number} 范围左边缘与屏幕左边的距离
top {number} 范围上边缘与屏幕上边的距离
right {number} 范围右边缘与屏幕左边的距离
bottom {number} 范围下边缘与屏幕上边的距离
为当前选择器附加控件"bounds需要在left, top, right, buttom构成的范围里面"的条件。
这个条件用于限制选择器在某一个区域选择控件。例如要在屏幕上半部分寻找文本控件TextView,代码为:
```language
var w = className("TextView").boundsInside(0, 0, device.width, device.height / 2).findOne();
log(w.text());
```
其中我们使用了device.width来获取屏幕宽度,device.height来获取屏幕高度。
## UiSelector.boundsContains(left, top, right, buttom)
|left {number}|范围左边缘与屏幕左边的距离|
|-|-|-|
|top {number}|范围上边缘与屏幕上边的距离|
|right {number}|范围右边缘与屏幕左边的距离|
|bottom {number}|范围下边缘与屏幕上边的距离|
为当前选择器附加控件"bounds需要包含left, top, right, buttom构成的范围"的条件。
这个条件用于限制控件的范围必须包含所给定的范围。例如给定一个点(500, 300), 寻找在这个点上的可点击控件的代码为:
```language
var w = boundsContains(500, 300, device.width - 500, device.height - 300).clickable().findOne();
w.click();
```
## UiSelector.drawingOrder(order)
order {number} 控件在父视图中的绘制顺序
为当前选择器附加控件"drawingOrder等于order"的条件。
drawingOrder为一个控件在父控件中的绘制顺序,通常可以用于区分同一层次的控件。
但该属性在Android 7.0以上才能使用。
## UiSelector.clickable([b = true])
b {Boolean} 表示控件是否可点击
|示控件是否可点击|
|-|-|-|
|b {Boolean} |
为当前选择器附加控件是否可点击的条件。但并非所有clickable为false的控件都真的不能点击,这取决于控件的实现。对于自定义控件(例如显示类名为android.view.View的控件)很多的clickable属性都为false都却能点击。
需要注意的是,可以省略参数b而表示选择那些可以点击的控件,例如className("ImageView").clickable()表示可以点击的图片控件的条件,className("ImageView").clickable(false)表示不可点击的图片控件的条件。
## UiSelector.longClickable([b = true])
|表示控件是否可长按|
|-|-|-|
|b {Boolean}|
为当前选择器附加控件是否可长按的条件。
## UiSelector.checkable([b = true])
|表示控件是否可勾选|
|-|-|-|
|b {Boolean}|
为当前选择器附加控件是否可勾选的条件。勾选通常是对于勾选框而言的,例如图片多选时左上角通常有一个勾选框。
## UiSelector.selected([b = true])
|表示控件是否被选|
|-|-|-|
|b {Boolean}|
为当前选择器附加控件是否已选中的条件。被选中指的是,例如QQ聊天界面点击下方的"表情按钮"时,会出现自己收藏的表情,这时"表情按钮"便处于选中状态,其selected属性为true。
## UiSelector.scrollable([b = true])
|表示控件是否可滑动|
|-|-|-|
|b {Boolean}|
为当前选择器附加控件是否可滑动的条件。滑动包括上下滑动和左右滑动。
可以用这个条件来寻找可滑动控件来滑动界面。例如滑动Auto.js的脚本列表的代码为:
```language
className("android.support.v7.widget.RecyclerView").scrollable().findOne().scrollForward();
//或者classNameEndsWith("RecyclerView").scrollable().findOne().scrollForward();
```
## UiSelector.editable([b = true])
|表示控件是否可编辑|
|-|-|-|
|b {Boolean}|
为当前选择器附加控件是否可编辑的条件。一般来说可编辑的控件为输入框(EditText),但不是所有的输入框(EditText)都可编辑。
## UiSelector.multiLine([b = true])
|表示文本或输入框控件是否是多行显示的|
|-|-|-|
|b {Boolean}|
为当前选择器附加控件是否文本或输入框控件是否是多行显示的条件。
## UiSelector.findOne()
|返回类型|
|-|-|-|
|UiObject|
根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,直到屏幕上出现满足条件的一个控件为止,并返回该控件。如果找不到控件,当屏幕内容发生变化时会重新寻找,直至找到。
需要注意的是,如果屏幕上一直没有出现所描述的控件,则该函数会阻塞,直至所描述的控件出现为止。因此此函数不会返回null。
该函数本来应该命名为untilFindOne(),但由于历史遗留原因已经无法修改。如果想要只在屏幕上搜索一次而不是一直搜索,请使用findOnce()。
另外,如果屏幕上有多个满足条件的控件,findOne()采用深度优先搜索(DFS),会返回该搜索算法找到的第一个控件。注意控件找到的顺序有时会起到作用。
## UiSelector.findOne(timeout)
|搜索的超时时间,单位毫秒|返回|
|-|-|-|
|timeout {number} |UiObject|
根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,直到屏幕上出现满足条件的一个控件为止,并返回该控件;如果在timeout毫秒的时间内没有找到符合条件的控件,则终止搜索并返回null。
该函数类似于不加参数的findOne(),只不过加上了时间限制。
示例:
```language
//启动Auto.js
launchApp("Auto.js");
//在6秒内找出日志图标的控件
var w = id("action_log").findOne(6000);
//如果找到控件则点击
if(w != null){
w.click();
}else{
//否则提示没有找到
toast("没有找到日志图标");
}
```
## UiSelector.findOnce()
返回 UiObject
根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,如果找到符合条件的控件则返回该控件;否则返回null。
## UiSelector.findOnce(i)
i {number} 索引
根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,并返回第 i + 1 个符合条件的控件;如果没有找到符合条件的控件,或者符合条件的控件个数 < i, 则返回null。
注意这里的控件次序,是搜索算法深度优先搜索(DSF)决定的。
## UiSelector.find()
|返回信息|
|-|-|-|
|UiCollection|
根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,找到所有满足条件的控件集合并返回。这个搜索只进行一次,并不保证一定会找到,因而会出现返回的控件集合为空的情况。
不同于findOne()或者findOnce()只找到一个控件并返回一个控件,find()函数会找出所有满足条件的控件并返回一个控件集合。之后可以对控件集合进行操作。
可以通过empty()函数判断找到的是否为空。例如:
```language
let object = id("v_sex_age").find();
if (!object.empty()) {
log("找到了");
object.forEach(function (currentValue, index) {
log(index);
});
} else {
log("没找到╭(╯^╰)╮");
}
```
例如官方的:
```language
var c = className("AbsListView").find();
if(c.empty()){
toast("找到啦");
}else{
toast("没找到╭(╯^╰)╮");
}
```
**比如获取desc的节点信息**
```language
let object = className("Button").depth(14).find(); //depth是14所以单独
if (!object.empty()) {
log("找到了");
object.forEach(function (currentValue, index) {
log(currentValue.desc()); //获取了desc信息
});
} else {
log("没找到╭(╯^╰)╮");
}
```
## UiSelector.untilFind()
返回 UiCollection
|返回 |
|-|-|-|
|UiCollection|
根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,直到找到至少一个满足条件的控件为止,并返回所有满足条件的控件集合。
该函数与find()函数的区别在于,该函数永远不会返回空集合;但是,如果屏幕上一直没有出现满足条件的控件,则该函数会保持阻塞。
## UiSelector.exists()
返回 {Boolean}
判断屏幕上是否存在控件符合选择器所确定的条件。例如要判断某个文本出现就执行某个动作,可以用:
```language
if(text("某个文本").exists()){
//要支持的动作
}
```
## UiSelector.waitFor()
等待屏幕上出现符合条件的控件;在满足该条件的控件出现之前,该函数会一直保持阻塞。
例如要等待包含"哈哈哈"的文本控件出现的代码为:
```language
textContains("哈哈哈").waitFor();
```
## UiSelector.filter(f)
f {Function} 过滤函数,参数为UiObject,返回值为boolean
为当前选择器附加自定义的过滤条件。
例如,要找出屏幕上所有文本长度为10的文本控件的代码为:
```language
var uc = className("TextView").filter(function(w){
return w.text().length == 10;
});
```