如何使用 Espresso 执行多点触控滑动?
How can I perform a multi touch swipe with Espresso?
如何使用 Espresso 执行多点触控滑动?例如用两根手指向右滑动。
Espresso 不提供该功能,但您可以通过
自行完成
- 注入两个向下事件
- 注入几对运动事件,每个手指一对
- 注入两个 up 事件
Espresso 有一些实用程序可以使它更容易。特别是,MotionEvents
class 有一些辅助方法用于创建和注入那些低级事件。
您可能需要参考 sendLinearSwipe
代码,其中包含单点触摸滑动的大部分逻辑。
如果你把它写成 ViewAction
,它将完全适合 Espresso 框架(例如,你可以很容易地让它等待空闲资源)。
正如@Daniel 所建议的,我创建了一个自定义版本的 MotionEvents,因为当使用多个手指时,您必须注入 ACTION_POINTER_DOWN/UP 而不是 ACTION_DOWN/UP。
我创建了一个 twoFinger 版本的 LinearSwipe,如下所示:
private static Swiper.Status sendLinearSwipe(UiController uiController,
float[] startCoordinates,
float[] startCoordinatesSecondFinger,
float[] endCoordinates,
float[]endCoordinatesSecondFinger,
float[] precision,
float[] precisionSecond,
int duration) {
checkNotNull(uiController);
checkNotNull(startCoordinates);
checkNotNull(startCoordinatesSecondFinger);
checkNotNull(endCoordinates);
checkNotNull(endCoordinatesSecondFinger);
checkNotNull(precision);
checkNotNull(precisionSecond);
float[][] steps = interpolate(startCoordinates, endCoordinates, SWIPE_EVENT_COUNT);
float[][] stepsSecondFinger = interpolate(startCoordinatesSecondFinger, endCoordinatesSecondFinger, SWIPE_EVENT_COUNT);
final int delayBetweenMovements = duration / steps.length;
final int delayBetweenMovementsSecondFinger = duration / stepsSecondFinger.length;
int maxLength=Math.min(steps.length, stepsSecondFinger.length);
MotionEvent downEvent;
downEvent = MotionEvents.sendDown(uiController, steps[0], precision,true).down;
MotionEvent downEventSecondFinger;
downEventSecondFinger = MotionEvents.sendDown(uiController,stepsSecondFinger[0], precisionSecond,false).down;
try {
for (int i = 1; i < maxLength; i++) {
if (sendMovement(uiController, steps[i], downEvent)) return Status.FAILURE;
if (sendMovement(uiController, stepsSecondFinger[i], downEventSecondFinger)) return Status.FAILURE;
long desiredTime = downEvent.getDownTime() + delayBetweenMovements * i;
long desiredTimeSecondFinger = downEventSecondFinger.getDownTime() + delayBetweenMovementsSecondFinger * i;
long timeUntilDesired = desiredTime - SystemClock.uptimeMillis();
long timeUntilDesiredSecondFinger = desiredTimeSecondFinger - SystemClock.uptimeMillis();
loopMainThread(uiController, timeUntilDesired);
loopMainThread(uiController, timeUntilDesiredSecondFinger);
}
if (!MotionEvents.sendUp(uiController, downEventSecondFinger, endCoordinatesSecondFinger,false)) {
Log.e(TAG, "Injection of up event as part of the swipe failed. Sending cancel event.");
MotionEvents.sendCancel(uiController, downEventSecondFinger);
return Swiper.Status.FAILURE;
}
} finally {
downEvent.recycle();
downEventSecondFinger.recycle();
}
return Swiper.Status.SUCCESS;
}
private static void loopMainThread(UiController uiController, long timeUntilDesired) {
if (timeUntilDesired > 10) {
uiController.loopMainThreadForAtLeast(timeUntilDesired);
}
}
private static boolean sendMovement(UiController uiController, float[] step, MotionEvent downEvent) {
if (!MotionEvents.sendMovement(uiController, downEvent, step)) {
Log.e(TAG, "Injection of move event as part of the swipe failed. Sending cancel event.");
MotionEvents.sendCancel(uiController, downEvent);
return true;
}
return false;
}
现在完美运行了!谢谢@Daniel
如何使用 Espresso 执行多点触控滑动?例如用两根手指向右滑动。
Espresso 不提供该功能,但您可以通过
自行完成- 注入两个向下事件
- 注入几对运动事件,每个手指一对
- 注入两个 up 事件
Espresso 有一些实用程序可以使它更容易。特别是,MotionEvents
class 有一些辅助方法用于创建和注入那些低级事件。
您可能需要参考 sendLinearSwipe
代码,其中包含单点触摸滑动的大部分逻辑。
如果你把它写成 ViewAction
,它将完全适合 Espresso 框架(例如,你可以很容易地让它等待空闲资源)。
正如@Daniel 所建议的,我创建了一个自定义版本的 MotionEvents,因为当使用多个手指时,您必须注入 ACTION_POINTER_DOWN/UP 而不是 ACTION_DOWN/UP。 我创建了一个 twoFinger 版本的 LinearSwipe,如下所示:
private static Swiper.Status sendLinearSwipe(UiController uiController,
float[] startCoordinates,
float[] startCoordinatesSecondFinger,
float[] endCoordinates,
float[]endCoordinatesSecondFinger,
float[] precision,
float[] precisionSecond,
int duration) {
checkNotNull(uiController);
checkNotNull(startCoordinates);
checkNotNull(startCoordinatesSecondFinger);
checkNotNull(endCoordinates);
checkNotNull(endCoordinatesSecondFinger);
checkNotNull(precision);
checkNotNull(precisionSecond);
float[][] steps = interpolate(startCoordinates, endCoordinates, SWIPE_EVENT_COUNT);
float[][] stepsSecondFinger = interpolate(startCoordinatesSecondFinger, endCoordinatesSecondFinger, SWIPE_EVENT_COUNT);
final int delayBetweenMovements = duration / steps.length;
final int delayBetweenMovementsSecondFinger = duration / stepsSecondFinger.length;
int maxLength=Math.min(steps.length, stepsSecondFinger.length);
MotionEvent downEvent;
downEvent = MotionEvents.sendDown(uiController, steps[0], precision,true).down;
MotionEvent downEventSecondFinger;
downEventSecondFinger = MotionEvents.sendDown(uiController,stepsSecondFinger[0], precisionSecond,false).down;
try {
for (int i = 1; i < maxLength; i++) {
if (sendMovement(uiController, steps[i], downEvent)) return Status.FAILURE;
if (sendMovement(uiController, stepsSecondFinger[i], downEventSecondFinger)) return Status.FAILURE;
long desiredTime = downEvent.getDownTime() + delayBetweenMovements * i;
long desiredTimeSecondFinger = downEventSecondFinger.getDownTime() + delayBetweenMovementsSecondFinger * i;
long timeUntilDesired = desiredTime - SystemClock.uptimeMillis();
long timeUntilDesiredSecondFinger = desiredTimeSecondFinger - SystemClock.uptimeMillis();
loopMainThread(uiController, timeUntilDesired);
loopMainThread(uiController, timeUntilDesiredSecondFinger);
}
if (!MotionEvents.sendUp(uiController, downEventSecondFinger, endCoordinatesSecondFinger,false)) {
Log.e(TAG, "Injection of up event as part of the swipe failed. Sending cancel event.");
MotionEvents.sendCancel(uiController, downEventSecondFinger);
return Swiper.Status.FAILURE;
}
} finally {
downEvent.recycle();
downEventSecondFinger.recycle();
}
return Swiper.Status.SUCCESS;
}
private static void loopMainThread(UiController uiController, long timeUntilDesired) {
if (timeUntilDesired > 10) {
uiController.loopMainThreadForAtLeast(timeUntilDesired);
}
}
private static boolean sendMovement(UiController uiController, float[] step, MotionEvent downEvent) {
if (!MotionEvents.sendMovement(uiController, downEvent, step)) {
Log.e(TAG, "Injection of move event as part of the swipe failed. Sending cancel event.");
MotionEvents.sendCancel(uiController, downEvent);
return true;
}
return false;
}
现在完美运行了!谢谢@Daniel