如何使用uiautomator获取视图的父级?

时间:2013-07-16 15:09:04

标签: android uiautomator android-uiautomator

我正在尝试识别ui元素的父视图,以便我可以自由地浏览UI。

例如,在“设置”应用中,我可以找到带有“蓝牙”文字的视图:

UiObject btView = new UiObject(new UiSelector().text("Bluetooth"));

现在,我遇到困难的部分是这样的:我想要向上导航两个级别并开始新的搜索开启/关闭按钮,启用和禁用蓝牙。

注意:如果我使用下面的代码,我可以获得该按钮。

UiObject btButtonView = new UiObject(new UiSelector().className("android.widget.Switch").instance(1));

这将搜索切换按钮并返回第二次遭遇。我希望搜索更精确,并在线性布局中查找包含“蓝牙”文本的按钮。

更新: 这是“设置”应用程序(我需要的蓝牙部分)的布局:

LinearLayout
    LinearLayout
        ImageView
    RelativeLayout
        TextView (with text = "Bluetooth")
    Switch ()

5 个答案:

答案 0 :(得分:15)

您需要首先使用文本找到UiObject两个级别。这可以使用UiCollection或UiScrollable中的getChildByText()方法完成。然后你可以很容易地找到开关。对于“设置”,此代码适用于我的设备:

UiScrollable settingsList = new UiScrollable(new UiSelector().scrollable(true));
UiObject btItem = settingsList.getChildByText(new UiSelector().className(LinearLayout.class.getName()),"Bluetooth", true);

UiObject btSwitch = btItem.getChild(new UiSelector().className(android.widget.Switch.class.getName()));
btSwitch.click();

答案 1 :(得分:4)

下面的代码适合我。

//Getting the scrollable view

UiScrollable settingsList = new UiScrollable(new UiSelector().scrollable(true));

for (int i=0; i<=settingsList.getChildCount(new UiSelector ().className(LinearLayout.class.getName())); i++) {
//Looping through each linear layout view
UiObject linearLayout = settingsList.getChild(new UiSelector().className(LinearLayout.class.getName()).instance(i));

//Checking if linear layout have the text. If yes, get the switch, click and break out of the loop.
if (linearLayout.getChild(new UiSelector ().text("Bluetooth")).exists()) {
    UiObject btSwitch = linearLayout.getChild(new UiSelector().className(android.widget.Switch.class.getName()));
    btSwitch.click ();
    break;
    }
}

答案 2 :(得分:0)

如果您只想搜索ON / OFF滑块 - &gt;您可以直接搜索蓝牙OFF / ON按钮并单击它以禁用/启用蓝牙 -

您可以在命令提示符下查看蓝牙页面的屏幕截图(使用命令 - uiautomatorviewer),并看到OFF按钮在OFF / ON滑块中有文本。然后只需使用 -

   new UiObject(new UiSelector().text("OFF")).click();

答案 3 :(得分:0)

最近发现我们可以使用getFromParent(对于UiObject)和fromParent(对于UiSelector)来选择对象的叔叔。 如果我们有这样的布局:

`LinearLayout
    relative layout
        text View
    relative layout
        check box`

我们可以使用以下代码从textview获取复选框:

TextViewTitle().getFromParent(new UiSelector()
            .fromParent(new UiSelector()
                    .resourceId("android:id/checkbox")));

其中TextViewTitle是带有文本视图的Uiobject

答案 4 :(得分:0)

uiautomator不支持:直接获取父节点

但是您可以自己添加(这需要很多工作)

一般步骤:

  1. xpath添加uiautomator
  2. 使用xpath查找父节点d.xpath("/current_node_path/..")

其他节点:

我使用

通过以下方法成功找到父节点:

self.driver.xpath("//android.widget.TextView[@text='Contact']/..")

和完整代码:

    def isMatchNode(self, curNodeAttrib, toMathInfo):
        isAllMatch = True
        for eachKey, eachToMatchValue in toMathInfo.items():
            if eachKey not in curNodeAttrib:
                isAllMatch = False
                break

            curValue = curNodeAttrib[eachKey]
            if curValue != eachToMatchValue:
                isAllMatch = False
                break


        return isAllMatch


    def findParentNode(self, curNodeXpath, matchDict, maxUpLevel=3):
        matchNode = None

        curNode = self.driver.xpath(curNodeXpath).get()
        curNodeAttrib = curNode.attrib # .attrib contain 'clickable'
        # curNodeInfo = curNode.info # .info not contain 'clickable'
        isCurMatch = self.isMatchNode(curNodeAttrib, matchDict)
        if isCurMatch:
            # current is match
            matchNode = curNode
        else:
            # try parent nodes
            curUpLevel = 1
            curParentNodeXpath = curNodeXpath
            hasFound = False
            while((not hasFound) and (curUpLevel <= maxUpLevel)):
                curParentNodeXpath += "/.."
                curParentNode = self.driver.xpath(curParentNodeXpath).get()
                curParentNodeAttrib = curParentNode.attrib
                isCurParentMatch = self.isMatchNode(curParentNodeAttrib, matchDict)
                if isCurParentMatch:
                    matchNode = curParentNode
                    break


        return matchNode


    def location_WexinAdd(self, reload=False):
        for eachNodeText in ["Contact", "Public Account"]:
            eachNodeXpath = "//android.widget.TextView[@text='%s']" % eachNodeText
            matchDict = {"clickable": "true"}
            clickableParentNode = self.findParentNode(curNodeXpath=eachNodeXpath, matchDict=matchDict)
            if clickableParentNode:
                clickableParentNode.click()
            else:
                logging.warning("Fail click %s for not found clickable=true (parent) node", eachNodeText)

供您参考。