选择器

# UiSelector UiSelector即选择器,用于通过各种条件选取屏幕上的控件,再对这些控件进行点击、长按等动作。这里需要先简单介绍一下控件和界面的相关知识。 一般软件的界面是由一个个控件构成的,例如图片部分是一个图片控件(ImageView),文字部分是一个文字控件(TextView);同时,通过各种布局来决定各个控件的位置,例如,线性布局(LinearLayout)里面的控件都是按水平或垂直一次叠放的,列表布局(AbsListView)则是以列表的形式显示控件。 控件有各种属性,包括文本(text), 描述(desc), 类名(className), id等等。我们通常用一个控件的属性来找到这个控件,例如,想要点击QQ聊天窗口的"发送"按钮,我们就可以通过他的文本属性为"发送"来找到这个控件并点击他,具体代码为: ``` var sendButton = text("发送").findOne(); sendButton.click(); ``` 在这个例子中, `text("发送")`表示一个条件(文本属性为"发送"),`findOne()`表示基于这个条件找到一个符合条件的控件,从而我们可以得到发送按钮sendButton,再执行`sendButton.click()`即可点击"发送"按钮。 用文本属性来定位按钮控件、文本控件通常十分有效。但是,如果一个控件是图片控件,比如Auto.js主界面右上角的搜索图标,他没有文本属性,这时需要其他属性来定位他。我们如何查看他有什么属性呢?首先打开悬浮窗和无障碍服务,点击蓝色的图标(布局分析), 可以看到以下界面: 之后我们点击搜索图标,可以看到他有以下属性: 我们注意到这个图标的desc(描述)属性为"搜索",那么我们就可以通过desc属性来定位这个控件,得到点击搜索图标的代码为: ``` desc("搜索").findOne().click(); ``` 可能心细的你可能注意到了,这个控件还有很多其他的属性,例如checked, className, clickable等等,为什么不用这些属性来定位搜索图标呢?答案是,其他控件也有这些值相同的属性、尝试一下你就可以发现很多其他控件的checked属性和搜索控件一样都是`false`,如果我们用`checked(false)`作为条件,将会找到很多控件,而无法确定哪一个是搜索图标。因此,要找到我们想要的那个控件,**选择器的条件通常需要是可唯一确定控件的**。我们通常用一个独一无二的属性来定位一个控件,例如这个例子中就没有其他控件的desc(描述)属性为"搜索"。 另外,对于这个搜索图标而言,id属性也是唯一的,我们也可以用`id("action_search").findOne().click()`来点击这个控件。如果一个控件有id属性,那么这个属性很可能是唯一的,除了以下几种情况: * QQ的控件的id属性很多都是"name",也就是在QQ界面难以通过id来定位一个控件 * 列表中的控件,比如QQ联系人列表,微信联系人列表等 尽管id属性很方便,但也不总是最方便的,例如对于微信和网易云音乐,每次更新他的控件id都会变化,导致了相同代码对于不同版本的微信、网易云音乐并不兼容。 除了这些属性外,主要还有以下几种属性: * `className` 类名。类名表示一个控件的类型,例如文本控件为"android.widget.TextView", 图片控件为"android.widget.ImageView"等。 * `packageName` 包名。包名表示控件所在的应用包名,例如QQ界面的控件的包名为"com.tencent.mobileqq"。 * `bounds` 控件在屏幕上的范围。 * `drawingOrder` 控件在父控件的绘制顺序。 * `indexInParent` 控件在父控件的位置。 * `clickable` 控件是否可点击。 * `longClickable` 控件是否可长按。 * `checkable` 控件是否可勾选。 * `checked` 控件是否可已勾选。 * `scrollable` 控件是否可滑动。 * `selected` 控件是否已选择。 * `editable` 控件是否可编辑。 * `visibleToUser` 控件是否可见。 * `enabled` 控件是否已启用。 * `depth` 控件的布局深度。 有时候只靠一个属性并不能唯一确定一个控件,这时需要通过属性的组合来完成定位,例如`className("ImageView").depth(10).findOne().click()`,通过链式调用来组合条件。 通常用这些技巧便可以解决大部分问题,即使解决不了问题,也可以通过布局分析的"生成代码"功能来尝试生成一些选择器代码。接下来的问题便是对选取的控件进行操作,包括: * `click()` 点击。点击一个控件,前提是这个控件的clickable属性为true * `longClick()` 长按。长按一个控件,前提是这个控件的longClickable属性为true * `setText()` 设置文本,用于编辑框控件设置文本。 * `scrollForward()`, `scrollBackward()` 滑动。滑动一个控件(列表等), 前提是这个控件的scrollable属性为true * `exits()` 判断控件是否存在 * `waitFor()` 等待控件出现 这些操作包含了绝大部分控件操作。根据这些我们可以很容易写出一个"刷屏"脚本(代码仅为示例,请不要在别人的群里测试,否则容易被踢): ``` while(true){ className("EditText").findOne().setText("刷屏..."); text("发送").findOne().clicK(); } ``` 上面这段代码也可以写成: ``` while(true){ className("EditText").setText("刷屏..."); text("发送").clicK(); } ``` 如果不加`findOne()`而直接进行操作,则选择器会找出**所有**符合条件的控件并操作。 另外一个比较常用的操作的滑动。滑动操作的第一步是找到需要滑动的控件,例如要滑动QQ消息列表则在悬浮窗布局层次分析中找到`AbsListView`,这个控件就是消息列表控件,如下图: 长按可查看控件信息,注意到其scrollable属性为true,并找出其id为"recent_chat_list",从而下滑QQ消息列表的代码为: ``` id("recent_chat_list").className("AbsListView").findOne().scrollForward(); ``` `scrollForward()`为向前滑,包括下滑和右滑。 选择器的入门教程暂且要这里,更多信息可以查看下面的文档和选择器进阶。