安卓:使用MotionEvent做拖动和自定义删除视图定位的ViewGroup

问题描述:

我有在我创建一个自定义的ViewGroup故障定位视图元素,特别是在拖和下降的情况。我瞄准了Android 2.2及以上,所以我真的不能使用诞生于Android的3拖和拖放API。

I am having trouble positioning view elements on a custom ViewGroup that I have created, specifically in drag-and-drop situations. I am targeting Android 2.2 and up, so I can't really use the drag-and-drop API that came into existence in Android 3.

我的自定义的ViewGroup被称为NodeGrid,它扩展了RelativeLayout的。它的 onLayout 方式被重写,使得它看起来是这样的:

My custom ViewGroup is called "NodeGrid" and it extends "RelativeLayout". Its onLayout method is overriden such that it looks like this:

@Override
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) 
{
    //pxConversion is a multiplier to convert 1 dip to x pixels.
    //We will use it to convert dip units into px units.
    Resources r = getResources();
    float pxConversion = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, r.getDisplayMetrics());

    //Layout the children of this viewgroup
    int childCount = this.getChildCount();
    for (int i = 0; i < childCount; i++)
    {
        NodeView view = (NodeView) this.getChildAt(i);

        if (view.DataContext != null)
        {
            int left = (int) (view.DataContext.get_left() * pxConversion);
            int top = (int) (view.DataContext.get_top() * pxConversion);
            int right = left + (int) (view.DataContext.get_width() * pxConversion);
            int bottom = top + (int) (view.DataContext.get_height() * pxConversion);

            view.layout(left, top, right, bottom);
        }
    }   
}

NodeGrid的孩子们的类型NodeView的(你可以在上面code见)。 NodeView很简单,我创建了一个自定义的视图类。它包含一个名为DataContext的部件,它是一个包含一些getter / setter方法​​有关的NodeGrid的NodeView例如位置信息的视图模型类。

The children of "NodeGrid" are of type "NodeView" (as you can see in the above code). NodeView is simply a custom View class that I have created. It contains a member called "DataContext" which is a view-model class that contains some getters/setters with position information about the NodeView instance on the NodeGrid.

我的NodeView类可捕获触摸事件由用户,这样用户就可以简单地拖放和拖放任何地方一个节点上的网格。事件处理程序是这样的:

My "NodeView" class captures touch events by the user, so the user can simply drag-and-drop a node anywhere on the grid. The event handler looks like this:

@Override
public boolean onTouchEvent(MotionEvent event) {

    if (event.getAction() == MotionEvent.ACTION_DOWN)
    {
        isBeingDragged = true;
    }
    else if (event.getAction() == MotionEvent.ACTION_UP)
    {
        isBeingDragged = false;
    }
    else if (event.getAction() == MotionEvent.ACTION_MOVE)
    {
        if (DataContext != null && isBeingDragged)
        {
            float xPosition = event.getRawX();
            float yPosition = event.getRawY();

            DataContext.set_left(xPosition);
            DataContext.set_top(yPosition);

            this.requestLayout();
        }
    }

    return true;
}

我的问题是,被拖动的观点并没有定位为我希望在我的NodeGrid。似乎x轴位置是正确的,因为我拖动,但是y轴位置是由像素随时一些恒定量抵销。什么会导致此?我已经使用的getX()和getY()以方法而不是getRawX()和getRawY()试过了,但只导致它要差一些。

My problem is that the view that is being dragged isn't positioned as I would expect it on my "NodeGrid". It seems that the x-axis position is correct as I drag it, but the y-axis position is offset by some constant amount of pixels at any time. What would be causing this? I have tried using the getX() and getY() methods rather than getRawX() and getRawY(), but that only causes it to be worse.

我不知道getRawX()和getRawY()是否返回像素单位或浸单位给我,让期待它是给我回像素单位,我试图将它们分配新的X前蘸单位和Y值的节点,但是那仅下降的偏移量,它没有消除它。

I wasn't sure whether getRawX() and getRawY() were returning px units or dip units to me, so expecting that it was giving me back px units, I tried converting them to dip units before assigning the new x and y values to the node, but that only decreased the offset, it did not eliminate it.

什么引起在我感动的差异,节点在何处被定位?

What could be causing the difference in where I am touching and where the node is being positioned?

非常惊讶,显然没有其他人遇到这样的情况......

Very surprised that apparently no one else has encountered this kind of situation...

经过一番研究,我已经部分已经能够解决这个问题。

After some research, I have partially been able to solve the problem.

没有工作的原因getRawX()和getRawY()是因为他们工作过的绝对的屏幕位置,而不考虑在屏幕上的任何东西,是不是你的应用程序的一部分(如Android的菜单,是不断地在顶部屏幕的,除非你是在全屏模式)。使用这些坐标似乎hackish的,尤其是没有明显的方法来证明它们,并将它们转换为我的应用的坐标。

The reason getRawX() and getRawY() did not work is because they work off the absolute screen position without regard to anything on the screen that is not part of your app (such as the Android menu which is constantly at the top of the screen unless you are in full screen mode). Using these coordinates seemed hackish, especially with no apparent way to justify them and convert them to "my app" coordinates.

的getX()和getY()以似乎对象被感动,据我可以告诉是相对的。如果考虑到这一点,我改变了code中的onTouchEvent阅读:

getX() and getY() seem to be relative to the object being touched as far as I can tell. When taking this into account, I changed the code in onTouchEvent to read:

float xPosition = event.getX();
float yPosition = event.getY();

DataContext.set_left(DataContext.get_left() + xPosition);
DataContext.set_top(DataContext.get_top() + yPosition);

this.requestLayout();

这肯定有助于...但它似乎仍不是一个完美的解决方案。在一般情况下,它会导致视图对象与我的鼠标光标/手指拖动沿,但它是非常紧张的,而且还有时间在那里可以得到怪诞去关闭屏幕。

This definitely helps...but it still doesn't seem to be a perfect solution. In general, it causes the view object to drag along with my mouse cursor/finger, but it is very jittery, and there are still times where it can get whacky and go off the screen.

然后我想,也许这是因为我并不包含历史坐标入法。我试图把这个$ C $结合历史坐标转换为C法立即在此之前,我在上面只显示了code:

I then thought that maybe it is because I am not incorporating "historical coordinates" into the method. I tried incorporating historical coordinates into the method by putting this code immediately before the code that I just displayed above:

int historySize = event.getHistorySize();
for (int i = 0; i < historySize; i++)
{
    float xPosition = event.getHistoricalX(i);
    float yPosition = event.getHistoricalY(i);

    DataContext.set_left(DataContext.get_left() + xPosition);
    DataContext.set_top(DataContext.get_top() + yPosition);

    this.requestLayout();
}

不幸的是......这实际上使情况变得更糟,所以无论是我没有使用正确的历史坐标,或者他们不应该使用的。我将发布关于此事的另一个问题,但这应该足以作为上面我的问题的部分答案。

Unfortunately...this actually makes it worse, so either I am not using the historical coordinates correctly or they shouldn't be used at all. I will post another question with regard to that matter, but this should suffice as a partial answer to my question above.