【问题标题】:Differentiate between zooming and moving a Google Map?区分缩放和移动 Google 地图?
【发布时间】:2017-12-23 22:01:25
【问题描述】:

我的目标是在相机移动时出现 ImageView,但仅在用户移动地图时出现,而不是在放大或缩小时出现。如何区分两者?

我尝试使用 OnCameraMove 和 OnCameraIdle 侦听器,但缩放被注册为移动,并且 OnCameraMoveStartedListener 只能在移动是否与用户相关时才能注册。

此外,在缩放时,我需要将缩放居中。希望这是有道理的。

【问题讨论】:

  • 我正在寻找的答案可以在here找到。

标签: android google-maps google-maps-android-api-2


【解决方案1】:

不幸的是,没有办法区分缩放和移动地图。但是,有一种 hacky 方法可以完成您正在寻找的内容。您可以创建一个扩展 FrameLayout 的包装类。在包装器内部重写 dispatchTouchEvent 方法并实现处理缩放/拖动或任何需要区分用户交互的逻辑。例如,要检测缩放,我们只需要确保有 2 个手指,它们已经移动到某个阈值之外并且它们正在向相反的方向移动。为此,我们必须重写 dispatchTouchEvent

switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
boolean isPrimMoving = isScrollGesture(event, 0, mPrimStartTouchEventX,
mPrimStartTouchEventY);
boolean isSecMoving = (mPtrCount > 1 && isScrollGesture(event, 1,
mSecStartTouchEventX, mSecStartTouchEventY));
if (mPtrCount > 1 && isPinchGesture(event)) {
Log.d("TAG", "PINCH! OUCH!");
} else if (isPrimMoving || isSecMoving) {
    // A 1 finger or 2 finger scroll.
    if (isPrimMoving && isSecMoving) {
      Log.d("TAG", "Two finger scroll");
    } else {
      Log.d("TAG", "One finger scroll");
    }}
break;

该类将声明一个接口,该接口将根据用户交互更新活动。然后,在您的片段中启动该类

mTouchView = new myWrapperClass(getActivity());
mTouchView.addView(mOriginalContentView);
return mTouchView;

你需要覆盖 onTouch

private float mPrimStartTouchEventX = -1;
private float mPrimStartTouchEventY = -1;
private float mSecStartTouchEventX = -1;
private float mSecStartTouchEventY = -1;
private float mPrimSecStartTouchDistance = 0;
...
@Override
public boolean onTouch(View v, MotionEvent event) {
  int action = (event.getAction() & MotionEvent.ACTION_MASK);

  switch (action) {
    case MotionEvent.ACTION_POINTER_DOWN:
    case MotionEvent.ACTION_DOWN:
      mPtrCount++;
      if (mPtrCount == 1) {
        mPrimStartTouchEventX = event.getX(0);
        mPrimStartTouchEventY = event.getY(0);
        Log.d("TAG", String.format("POINTER ONE X = %.5f, Y = %.5f", mPrimStartTouchEventX, mPrimStartTouchEventY));
      }
      if (mPtrCount == 2) {
        // Starting distance between fingers
        mSecStartTouchEventX = event.getX(1);
        mSecStartTouchEventY = event.getY(1);
        mPrimSecStartTouchDistance = distance(event, 0, 1);
        Log.d("TAG", String.format("POINTER TWO X = %.5f, Y = %.5f", mSecStartTouchEventX, mSecStartTouchEventY));
      }

      break;
    case MotionEvent.ACTION_POINTER_UP:
    case MotionEvent.ACTION_UP:
      mPtrCount--;
      if (mPtrCount < 2) {
        mSecStartTouchEventX = -1;
        mSecStartTouchEventY = -1;
      }
      if (mPtrCount < 1) {
        mPrimStartTouchEventX = -1;
        mPrimStartTouchEventY = -1;
      }
      break;

    case MotionEvent.ACTION_MOVE:
      Log.d("TAG", "Move " + mPtrCount);
      break;

  }

  return true;
}

编辑:下面是isPinchGesture & isScrollGesture的实现

private boolean isPinchGesture(MotionEvent event) {
  if (event.getPointerCount() == 2) {
    final float distanceCurrent = distance(event, 0, 1);
    final float diffPrimX = mPrimStartTouchEventX - event.getX(0);
    final float diffPrimY = mPrimStartTouchEventY - event.getY(0);
    final float diffSecX = mSecStartTouchEventX - event.getX(1);
    final float diffSecY = mSecStartTouchEventY - event.getY(1);

    if (Math.abs(distanceCurrent - mPrimSecStartTouchDistance) > mViewScaledTouchSlop
            // and the fingers are moving in opposing directions
            && (diffPrimY * diffSecY) <= 0
            && (diffPrimX * diffSecX) <= 0) {
      return true;
    }
  }

  return false;
}
private boolean isScrollGesture(MotionEvent event, int ptrIndex, float originalX, float originalY){
  float moveX = Math.abs(event.getX(ptrIndex) - originalX);
  float moveY = Math.abs(event.getY(ptrIndex) - originalY);

  if (moveX > mViewScaledTouchSlop || moveY > mViewScaledTouchSlop) {
   return true;
  }
  return false;
}

编辑 2:您可以使用 ScaleGestureDetector 使用 OnTouchListener 在 Android 中检测捏合手势。 欲了解更多信息:https://developer.android.com/training/gestures/scale.html

static class MyPinchListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
  @Override
  public boolean onScale(ScaleGestureDetector detector) {
    Log.d("TAG", "PINCH! OUCH!");
    return true;
  }
}
/* Using it */
ScaleGestureDetector mScaleDetector = 
             new ScaleGestureDetector(this, new MyPinchListener());
mGestureView.setOnTouchListener(new View.OnTouchListener() {
  @Override
  public boolean onTouch(View v, MotionEvent event) {
    mScaleDetector.onTouchEvent(event);
    return true;
  }
});

【讨论】:

  • 能否给我一个更详细的解释,比如 isPinchGesture() 和 isScrollGesture() 是如何实现的? mPtrCount、mPrim 和 mSec 变量到底是什么?
  • 好的,@mente86 我将编辑我的帖子并添加这两种方法的实现。请接受我的回答。
  • 好吧,我在地图上进行了缩放,但现在移动地图不起作用,因为 mGestureView 的 onTouch 事件会吃掉它。我怎样才能防止这种情况发生,如果只有一根手指触摸它,则移动地图,如果是两根手指,则让 mScaleDetector 工作?
  • onTouch 方法内部检测事件的类型,如果它只是滚动返回 false。
  • 这不起作用,因为检测它是什么类型的事件需要多次调用 onTouch 方法(如用于拖动的 ACTION_DOWN + ACTION_MOVE),但是当我第一次在该事件上返回 true 时,地图拖动事件被吃掉。如果我可以在 while 循环中运行该 switch 语句来检测它是什么类型的事件,然后根据它是否是拖动返回 false 或 true。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-25
  • 1970-01-01
  • 2012-08-27
  • 1970-01-01
相关资源
最近更新 更多