【问题标题】:Jumping ImageView while dragging. getX() and getY() values are jumping拖动时跳转 ImageView。 getX() 和 getY() 值在跳跃
【发布时间】:2013-07-08 15:36:11
【问题描述】:

我创建了一个用于拖动视图的 onTouchListener。如果我使用getRawX()getRawY(),图像可以顺利拖动。这样做的问题是,当您将第二个指针放下然后抬起第一个指针时,图像会跳转到第二个指针。

此 onTouchListener 尝试通过跟踪 pointerId 来解决该问题。这个 onTouchListener 的问题是在拖动 ImageView 时,ImageView 会非常疯狂地跳来跳去。 getX()getY() 值会跳来跳去。

我觉得我这样做是正确的。我不想为此编写自定义视图,因为我已经实现了一个 scaleGestureDetector 并编写了一个可以工作的自定义 rotateGestureDetector。一切正常,但我需要解决使用getRawX()getRawY() 时遇到的问题。

有人知道我在这里做错了什么吗?

这是我的 onTouchListener:

final View.OnTouchListener onTouchListener = new View.OnTouchListener()
{
    @Override
    public boolean onTouch(View v, MotionEvent event)
    {
        relativeLayoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();

        final int action = event.getAction();
        switch (action & MotionEvent.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:
            {
                final float x = event.getX();
                final float y = event.getY();

                // Where the user started the drag
                lastX = x;
                lastY = y;
                activePointerId = event.getPointerId(0);
                break;
            }
            case MotionEvent.ACTION_MOVE:
            {
                // Where the user's finger is during the drag
                final int pointerIndex = event.findPointerIndex(activePointerId);
                final float x = event.getX(pointerIndex);
                final float y = event.getY(pointerIndex);

                // Calculate change in x and change in y
                final float dx = x - lastX;
                final float dy = y - lastY;

                // Update the margins to move the view
                relativeLayoutParams.leftMargin += dx;
                relativeLayoutParams.topMargin += dy;
                v.setLayoutParams(relativeLayoutParams);

                // Save where the user's finger was for the next ACTION_MOVE
                lastX = x;
                lastY = y;

                v.invalidate();
                break;
            }
            case MotionEvent.ACTION_UP:
            {
                activePointerId = INVALID_POINTER_ID;
                break;
            }
            case MotionEvent.ACTION_CANCEL:
            {
                activePointerId = INVALID_POINTER_ID;
                break;
            }
            case MotionEvent.ACTION_POINTER_UP:
            {
                // Extract the index of the pointer that left the touch sensor
                final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = event.getPointerId(pointerIndex);

                if(pointerId == activePointerId)
                {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    lastX = (int) event.getX(newPointerIndex);
                    lastY = (int) event.getY(newPointerIndex);
                    activePointerId = event.getPointerId(newPointerIndex);
                }
                break;
            }
        }
        return true;
    }
};
image1.setOnTouchListener(onTouchListener);

【问题讨论】:

  • 有人有解决办法吗?好像其他人遇到过这个问题,但我还没有找到解决方案。

标签: android drag-and-drop imageview android-imageview ontouchlistener


【解决方案1】:

问题很简单,但出乎意料。 getRawX/Y() 返回绝对坐标,而getX/Y() 返回相对于视图的坐标。我会移动视图,重置lastX/Y,图像不会再出现在同一个位置,所以当我获得新值时,它们会关闭。在这种情况下,我只需要最初按下图像的位置(使用 `getRawX/Y' 时不需要)。

因此,解决方案是简单地删除以下内容:

// Save where the user's finger was for the next ACTION_MOVE
lastX = x;
lastY = y;

我希望这对将来的人有所帮助,因为我见过其他人遇到这个问题,他们的代码与我相似(重置lastX/Y

【讨论】:

  • 很高兴我找到了这个!我怀疑很多人因为阅读 android-developers.blogspot.com/2010/06/… 而拥有保存 lastX/LastY 的代码。显然,移动视图的情况与正在翻译画布的“多点触控”中的示例不同。这里的最后一条评论stackoverflow.com/questions/16676097/…指出,当他注释掉view.setX()和view.setY()的设置时,onTouch()期间绝对坐标和相对坐标的交错停止了。
  • @T.Folsom 很高兴我能帮上忙!是的,很多人在你的第一个链接之后建模他们的代码,包括我自己。据我所知,getX()getY() 总是返回相对坐标。他的坐标跳跃的原因和我一样。他移动视图然后获得不同的相对坐标,因为视图已经移动。这有意义吗?
  • 是的,这确实帮助了更多人:)
  • 2019,仍然有帮助。我从官方文档 (developer.android.com/training/gestures/scale) 中获得了示例代码并继承了这个问题。谢谢!
  • @Vasiliy Wonderful :) 我很高兴答案得到了支持
【解决方案2】:

经过大量研究,我发现这是问题所在,getRawX 是绝对的,getX 是相对于视图的。因此使用它来将一个转换为另一个

//RawX = getX + View.getX

event.getRawX == event.getX(event.findPointerIndex(ptrID1))+view.getX()

【讨论】:

    【解决方案3】:

    我有一个提示,我认为它会有所帮助。

    invalidate() : does only redrawing a view,doesn't change view size/position.
    

    你应该使用的是 requestLayout():进行测量和布局过程。 &我认为requestLayout()会在调用setLayoutParams()时被调用;

    所以尝试删除v.invalidate()

    或者尝试使用view.layout(left,top,right,bottom) 方法而不是设置layoutParams。

    【讨论】:

    • 我过去曾尝试删除 v.invalidate() (因为您提出了建议,现在又尝试了一次),因为我认为它在这种情况下没用,但无济于事。我尝试用v.requestLayout() 替换它,但这也没有改变行为:/ 还有其他建议吗?
    • 或尝试使用 view.layout(left,top,right,bottom) 方法而不是设置 layoutParams。
    猜你喜欢
    • 2015-07-01
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    相关资源
    最近更新 更多