最近有同学常问滑动相关的问题:使用 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);
}
录屏
代码肯定不适用于所有场景,希望对各位有所帮助。代码水平有限,还请见谅,欢迎拍砖。