Appium源码分析(五)-drag

本文深入探讨了Appium中drag操作的实现原理,包括源代码分析及如何通过TouchAction实现自定义拖拽。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先我们来看下drag的源代码吧。
@Override
  public AndroidCommandResult execute(final AndroidCommand command)
      throws JSONException {
    // DragArguments is created on each execute which prevents leaking state
    // across executions.
    final DragArguments dragArgs = new DragArguments(command);

    if (command.isElementCommand()) {
      return dragElement(dragArgs);
    } else {
      return drag(dragArgs);
    }
  }
首先先获取到DragArguments的一个实例化对象,主要是获取command命令中的参数:起始的元素,结束的元素,开始结束的坐标,以及步数。具体看代码
public DragArguments(final AndroidCommand command) throws JSONException {

      final Hashtable<String, Object> params = command.params();

      try {
        if (params.get("elementId") != JSONObject.NULL) {
          el = command.getElement();
        }
      } catch (final Exception e) {
        el = null;
      }

      try {
        if (params.get("destElId") != JSONObject.NULL) {
          destEl = command.getDestElement();
        }
      } catch (final Exception e) {
        destEl = null;
      }
      start = new Point(params.get("startX"), params.get("startY"));
      end = new Point(params.get("endX"), params.get("endY"));
      steps = (Integer) params.get("steps");
    }
以上的代码比较好理解,这里就不做详细解释了,下来判断comman命令是否是针对于元素的操作。其实这里也可以通过是否存在有开始的元素以及结束的元素来判断是否是针对于元素的操作。
  • 如果是针对于元素的Drag

private AndroidCommandResult dragElement(final DragArguments dragArgs) {
    Point absEndPos = new Point();

    if (dragArgs.destEl == null) {
      try {
        //这里判断如果无destEl时,那么就需要计算结束坐标相对于设备的坐标位置。这里的计算方法与swipe的转换是一样的
        absEndPos = PositionHelper.getDeviceAbsPos(dragArgs.end);
      } catch (final InvalidCoordinatesException e) {
        return getErrorResult(e.getMessage());
      } catch (final UiObjectNotFoundException e) {
        return getErrorResult(e.getMessage());
      } 

      Logger.debug("Dragging the element with id " + dragArgs.el.getId()
          + " to " + absEndPos.toString() + " with steps: "
          + dragArgs.steps.toString());
      try {
        //调用UiAutomator中的drag方法,这里需要注意api要大于18,如果小于则拖拽不成功
        final boolean rv = dragArgs.el.dragTo(absEndPos.x.intValue(),
            absEndPos.y.intValue(), dragArgs.steps);
        if (!rv) {
          return getErrorResult("Drag did not complete successfully");
        } else {
          return getSuccessResult(rv);
        }
      } catch (final UiObjectNotFoundException e) {
        return getErrorResult("Drag did not complete successfully"
            + e.getMessage());
      }
    } else {
        //如果destEl不为空时,则调用Uiautomator另一个方法 boolean dragTo(UiObject destObj, int steps)
      Logger.debug("Dragging the element with id " + dragArgs.el.getId()
          + " to destination element with id " + dragArgs.destEl.getId()
          + " with steps: " + dragArgs.steps);
      try {
        final boolean rv = dragArgs.el.dragTo(dragArgs.destEl.getUiObject(),
            dragArgs.steps);
        if (!rv) {
          return getErrorResult("Drag did not complete successfully");
        } else {
          return getSuccessResult(rv);
        }
      } catch (final UiObjectNotFoundException e) {
        return getErrorResult("Drag did not complete successfully"
            + e.getMessage());
      }
    }

  }
以上是针对于元素的操作
  • 如果是针对非元素的Drag
private AndroidCommandResult drag(final DragArguments dragArgs) {
    Point absStartPos = new Point();
    Point absEndPos = new Point();
    final UiDevice device = UiDevice.getInstance();

    try {
    //这里分别将起始以及结束的坐标转换成相应的设备的坐标
      absStartPos = PositionHelper.getDeviceAbsPos(dragArgs.start);
      absEndPos = PositionHelper.getDeviceAbsPos(dragArgs.end);
    } catch (final InvalidCoordinatesException e) {
      return getErrorResult(e.getMessage());
    } catch (final UiObjectNotFoundException e) {
        return getErrorResult(e.getMessage());
      } 

    Logger.debug("Dragging from " + absStartPos.toString() + " to "
        + absEndPos.toString() + " with steps: " + dragArgs.steps.toString());
    //再来也是一样的调用Uiautomator的drag方法
    final boolean rv = device.drag(absStartPos.x.intValue(),
        absStartPos.y.intValue(), absEndPos.x.intValue(),
        absEndPos.y.intValue(), dragArgs.steps);
    if (!rv) {
      return getErrorResult("Drag did not complete successfully");
    }
    return getSuccessResult(rv);
  }
但是问题来了,appium的api中貌似只提供了一个方法
# convenience method added to Appium (NOT Selenium 3)
  def drag_and_drop(self, origin_el, destination_el):
      """Drag the origin element to the destination element

      :Args:
       - originEl - the element to drag
       - destinationEl - the element to drag to
      """
      action = TouchAction(self)
      action.long_press(origin_el).move_to(destination_el).release().perform()
      return self
那如果我想要实现一个点到另外一个点的拖拽那怎么做呢。实际我们只要研究下appium-client的源码就能得出结果了,我们看下drag_and_drop的源代码
def drag_and_drop(self, origin_el, destination_el):
    """Drag the origin element to the destination element

    :Args:
     - originEl - the element to drag
     - destinationEl - the element to drag to
    """
    action = TouchAction(self)
    action.long_press(origin_el).move_to(destination_el).release().perform()
    return self
内容很简单,先长按移动到对应点在松开。原来drag实际上到最后还是变成action进行实现的,那么这样子就简单了,我们也可以去构造出一个drag针对于坐标的
action1 = touch_action.TouchAction(self.driver)
action = touch_action.TouchAction(self.driver)
action.long_press(x=0.5,y=0.5).move_to(x=1.0,y=1.0).release().perform()
这样子就实现了拖拽的方法了,我们来看看appium 的log吧。

这里写图片描述

这样子是不是就清晰了很多呢
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值