前言

最近有同学常问滑动相关的问题:使用 AndroidUIAutomator 不通用;引用原来的滑动 API 报错。本贴主要解决同学们的问题,最后写两个简单的滑动方法。

问题

使用 AndroidUIAutomator,原生滑动方法,代码如下:

AndroidElement list=driver.findElement(By.id("com.xueqiu.android:id/lv_list_view"));
MobileElement textClock= list.findElement(MobileBy.AndroidUIAutomator("new UiScrollable(new UiSelector()).scrollIntoView("
        +"new UiSelector().text(\"xxxxxxx\"));"));
textClock.click();

但此方法仅能 Android 平台使用,可是使用 Appium 滑动 API,编译时报错:

原因

远程连接同学的电脑,查看代码编译时报错的原因是因为,Appium 的 java-client 6.1.0 滑动的 API 变更了;下面我们以长按屏幕坐标 API 为例。
java-client 5.x 的长按屏幕坐标 API 是这样:

java-client 6.1.0 的长按屏幕坐标 API 是这样:

PointOption 中方法:

API 地址:
java-client-5.0.4API
java-client-6.1.0API

解决方法

看完 API 其实只要在原来代码坐标外,增加 PointOption.point 方法就可以了,代码如下:

这样的话就不会报错了,但是不同手机屏幕大小可能不同;如果还用上面的坐标,脚本可能就会失败;所以要封装一下,下面提供两种简单的封装方法:屏幕滑动至特定控件和控件内滑动;

滑动方法

屏幕滑动至特定控件
由于移动端 UI 测试,元素必须得在屏幕中显示,才能进行操作;所以先解决滑动问题,之后确定界面有该元素即可。代码如下:

/**
     * @Function 屏幕滑动至特定控件
     * @Author 霍格沃兹测试学院
     * @param element 要查找的元素
     * @param startX x起始坐标
     * @param endX x终点坐标
     * @param startY y起始坐标
     * @param endY y终点坐标
     */

   public static void swipePage(String element,double startX,double endX,double startY,double endY) {

   //获取手机屏幕大小
   Dimension screenSize=driver.manage().window().getSize();

   while(true) {
     try {
       (new TouchAction(driver))
       .longPress(PointOption.point((int)(screenSize.width * startX),(int)(screenSize.height * startY)))
       .moveTo(PointOption.point((int) (screenSize.width * endX),(int) (screenSize.height * endY)))
       .release()
       .perform();
     } catch (Exception e) {
       if (startX >= 1 || startX <= 0) {
         System.out.println("超出手机屏幕边界,x起始坐标必须小于1且大于0");
                } else if (endX >= 1 || endX <= 0) {
          System.out.println("超出手机屏幕边界,x终点坐标必须小于1且大于0");
                } else if (startY >= 1 || startY <= 0) {
          System.out.println("超出手机屏幕边界,y起始坐标必须小于1且大于0");
                } else if (endY >= 1 || endY <= 0) {
          System.out.println("超出手机屏幕边界,y终点坐标必须小于1且大于0");
                }
        return;
            }
      String pagesource = driver.getPageSource();
                //判断元素是否存在,存在则不等于-1,String.indexOf(xxxx)返回包含该字符串在父类字符串中起始位置,不包含则全部返回-1
        if (pagesource.indexOf(element) != -1) {
          return;
        }
      }
    }

朝什么方向滑,直接用开始或结束 x、y 轴坐标控制即可,直到界面出现该元素值。

控件内滑动
有些控件内部需要滑动,我们把控件开始坐标和控件宽和高值取出来,计算出结束坐标;之后使用手势的 API 即可,代码如下:

/**
 * @Function 控件内滑动
 * @Author 霍格沃兹测试学院
 * @param element 要操作的控件元素属性
 * @param distance 要滑动的距离,1滑到头/2是滑2分之一/3是滑3分之一
 */
public static void swipeCrosswiseControl(String element,int distance){
  Point start=driver.findElementByXPath("//*[@resource-id='"+element+"']").getLocation();
  int startX = start.x;
  int startY = start.y;
  Dimension wh=driver.findElementByXPath("//*[@resource-id='"+element+"']").getSize();
  int Widthx=wh.getWidth();
  int Heighty=wh.getHeight();
  int endX = Widthx + startX;
  int endY = Heighty + startY;
  (new TouchAction(driver))
      .longPress(PointOption.point(startX,endY-Heighty/2))
      .moveTo(PointOption.point(startX+Widthx/distance,endY))
      .release()
      .perform();
}

上面的代码从左到右,横向滑动;如果想要其他方向滑动,可以修改 longPress 和 moveTo 即可。

滑动效果

场景
使用上面两个方法,运行 API Demos 点击"Views",滑动至"Rotating Button"按钮并点击,滑动 TX 至中间。
代码:

public void testSwipeControls(){
      WebDriverWait wait = new WebDriverWait(driver, 10);
      wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@text='Views']"))).click();
      Swipe.swipePage("Rotating Button", 0.5, 0.5, 0.8, 0.2);
      wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@text='Rotating Button']"))).click();
      Swipe.swipeCrosswiseControl("io.appium.android.apis:id/translationX",2);
}

录屏

总结

代码肯定不适用于所有场景,希望对各位有所帮助。代码水平有限,还请见谅,欢迎拍砖。


↙↙↙阅读原文可查看相关链接,并与作者交流