# Swipe
我定義為滑動,但它字面的意思又不是,事件的形式類似于小時候拿著一塊石頭片,朝水面飛過去,如果你手法可以那么就是swipe走的路線,如果你手法不行,接觸水面的時候就沒再飛起來那就會被人嘲笑的。
~~~
package io.appium.android.bootstrap.handler;
import com.android.uiautomator.core.UiDevice;
import com.android.uiautomator.core.UiObjectNotFoundException;
import io.appium.android.bootstrap.*;
import io.appium.android.bootstrap.exceptions.InvalidCoordinatesException;
import io.appium.android.bootstrap.utils.Point;
import org.json.JSONException;
import java.util.Hashtable;
/**
* This handler is used to swipe.
*
*/
public class Swipe extends CommandHandler {
/*
* @param command The {@link AndroidCommand} used for this handler.
*
* @return {@link AndroidCommandResult}
*
* @throws JSONException
*
* @see io.appium.android.bootstrap.CommandHandler#execute(io.appium.android.
* bootstrap.AndroidCommand)
*/
@Override
public AndroidCommandResult execute(final AndroidCommand command)
throws JSONException {
final Hashtable<String, Object> params = command.params();
final Point start = new Point(params.get("startX"), params.get("startY"));
final Point end = new Point(params.get("endX"), params.get("endY"));
final Integer steps = (Integer) params.get("steps");
final UiDevice device = UiDevice.getInstance();
Point absStartPos = new Point();
Point absEndPos = new Point();
if (command.isElementCommand()) {
try {
final AndroidElement el = command.getElement();
absStartPos = el.getAbsolutePosition(start);
absEndPos = el.getAbsolutePosition(end, false);
} catch (final UiObjectNotFoundException e) {
return getErrorResult(e.getMessage());
} catch (final InvalidCoordinatesException e) {
return getErrorResult(e.getMessage());
} catch (final Exception e) { // handle NullPointerException
return getErrorResult("Unknown error");
}
} else {
try {
absStartPos = getDeviceAbsPos(start);
absEndPos = getDeviceAbsPos(end);
} catch (final InvalidCoordinatesException e) {
return getErrorResult(e.getMessage());
}
}
Logger.debug("Swiping from " + absStartPos.toString() + " to "
+ absEndPos.toString() + " with steps: " + steps.toString());
final boolean rv = device.swipe(absStartPos.x.intValue(),
absStartPos.y.intValue(), absEndPos.x.intValue(),
absEndPos.y.intValue(), steps);
if (!rv) {
return getErrorResult("The swipe did not complete successfully");
}
return getSuccessResult(rv);
}
}
~~~
不管它如何定義,先分析源碼最后再定義。
~~~
final Hashtable<String, Object> params = command.params();
final Point start = new Point(params.get("startX"), params.get("startY"));
final Point end = new Point(params.get("endX"), params.get("endY"));
final Integer steps = (Integer) params.get("steps");
final UiDevice device = UiDevice.getInstance();
Point absStartPos = new Point();
Point absEndPos = new Point();
~~~
首先從命令里取得參數,然后解析出所需要的3個變量:起始點start、終點end、步驟steps。然后獲得設備對象,定義2個私有Point對象,以備后用。
然后分條件處理,處理控件還是處理坐標。
## 控件
~~~
final AndroidElement el = command.getElement();
absStartPos = el.getAbsolutePosition(start);
absEndPos = el.getAbsolutePosition(end, false);
~~~
首先獲取控件對象,再通過getAbsolutePosition傳入不同的參數獲得在該控件上點擊的起始點和結束點。
~~~
public Point getAbsolutePosition(final Point point,
final boolean boundsChecking) throws UiObjectNotFoundException,
InvalidCoordinatesException {
final Rect rect = el.getBounds();
final Point pos = new Point();
Logger.debug("Element bounds: " + rect.toShortString());
if (point.x == 0) {
pos.x = rect.width() * 0.5 + rect.left;
} else if (point.x <= 1) {
pos.x = rect.width() * point.x + rect.left;
} else {
pos.x = rect.left + point.x;
}
if (boundsChecking) {
if (pos.x > rect.right || pos.x < rect.left) {
throw new InvalidCoordinatesException("X coordinate ("
+ pos.x.toString() + " is outside of element rect: "
+ rect.toShortString());
}
}
if (point.y == 0) {
pos.y = rect.height() * 0.5 + rect.top;
} else if (point.y <= 1) {
pos.y = rect.height() * point.y + rect.top;
} else {
pos.y = rect.left + point.y;
}
if (boundsChecking) {
if (pos.y > rect.bottom || pos.y < rect.top) {
throw new InvalidCoordinatesException("Y coordinate ("
+ pos.y.toString() + " is outside of element rect: "
+ rect.toShortString());
}
}
return pos;
}
~~~
上面的一大段代碼,看起來很復雜,其實很簡單,業務很容易理解,處理這種點的時候就需要判斷很多東西。上面的代碼首先分析x坐標然后分析y坐標。x和y坐標的判斷和處理時一樣的,所以我只講一下x坐標。
首先判斷x坐標是否為0,如果為0,定義初始點的x坐標為控件的中心點的橫坐標。如果x的坐標小于1,說明坐標為相對坐標,用百分比來求值,此時就要與寬度做乘積運算得到具體值。如果上面2種情況都不符合,那就是具體坐標值,那就直接元素的x坐標值加上控件的邊框左坐標值。最后根據傳入的boolean值來判斷是否做一個超出邊界的驗證。如果超出邊界就跑出異常。y坐標的獲取方式類似。最后得到坐標值并返回,回到execute方法中。
## 坐標
~~~
absStartPos = getDeviceAbsPos(start);
absEndPos = getDeviceAbsPos(end);
~~~
通過調用getDeviceAbsPos()方法得到坐標值來初始化之前聲明的私有Point對象.
~~~
protected static Point getDeviceAbsPos(final Point point)
throws InvalidCoordinatesException {
final UiDevice d = UiDevice.getInstance();
final Point retPos = new Point(point); // copy inputed point
final Double width = (double) d.getDisplayWidth();
if (point.x < 1) {
retPos.x = width * point.x;
}
if (retPos.x > width || retPos.x < 0) {
throw new InvalidCoordinatesException("X coordinate ("
+ retPos.x.toString() + " is outside of screen width: "
+ width.toString());
}
final Double height = (double) d.getDisplayHeight();
if (point.y < 1) {
retPos.y = height * point.y;
}
if (retPos.y > height || retPos.y < 0) {
throw new InvalidCoordinatesException("Y coordinate ("
+ retPos.y.toString() + " is outside of screen height: "
+ height.toString());
}
return retPos;
}
~~~
類似于上面的方法,也是要先判斷傳過來的坐標值是否小于1,如果小于1,當作百分比來球坐標值。如果超出屏幕的范圍拋出異常,最后返回坐標值回到execute方法。
===============================================================================================================================
~~~
final boolean rv = device.swipe(absStartPos.x.intValue(),
absStartPos.y.intValue(), absEndPos.x.intValue(),
absEndPos.y.intValue(), steps);
~~~
最后調用UiDevice.swipe方法來執行命令,判斷是否執行成功。
# 總結
執行swipe命令有2中命令格式
* 控件
* 坐標
坐標又分為相對坐標百分比和絕對坐標兩種方法。
- 前言
- appium框架之bootstrap
- bootstrap之Click事件
- bootstrap之WaitForIdle&&Clear
- bootstrap之Orientation
- bootstrap之Swipe
- bootstrap之Flick
- bootstrap之Drag
- bootstrap之Pinch
- bootstrap之鼠標操作
- bootstrap之文本框的操作
- bootstrap之GetName&&GetAttribute&&GetDeviceSize&&GetSize&&GetLocation&&GetDataDir
- bootstrap之ScrollTo
- bootstrap之Wake&&PressBack&&TakeScreenshot&&OpenNotification
- bootstrap之PressKeyCode&&LongPressKeyCode
- bootstrap之DumpWindowHierarchy
- bootstrap之UpdateStrings
- bootstrap之MultiPointerGesture