Android: usando o MotionEvent para arrastar e soltar o posicionamento de Views em um ViewGroup personalizado
Estou com problemas para posicionar elementos de exibição em um ViewGroup personalizado que criei, especificamente em situações de arrastar e soltar. Como estou segmentando o Android 2.2 e superior, não posso realmente usar a API de arrastar e soltar que surgiu no Android 3.
Meu ViewGroup personalizado é chamado "NodeGrid" e estende "RelativeLayout". Está onLayout método @ é substituído de maneira que fique assim:
@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);
}
}
}
Os filhos de "NodeGrid" são do tipo "NodeView" (como você pode ver no código acima). O NodeView é simplesmente uma classe View personalizada que eu criei. Ele contém um membro chamado "DataContext", que é uma classe de modelo de exibição que contém alguns getters / setters com informações de posição sobre a instância do NodeView no NodeGrid.
Minha classe "NodeView" captura eventos de toque do usuário, para que ele possa simplesmente arrastar e soltar um nó em qualquer lugar da grade. O manipulador de eventos fica assim:
@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;
}
Meu problema é que a exibição que está sendo arrastada não está posicionada como seria de esperar no meu "NodeGrid". Parece que a posição do eixo x está correta quando eu a arrasto, mas a posição do eixo y é deslocada por uma quantidade constante de pixels a qualquer momento. O que estaria causando isso? Tentei usar os métodos getX () e getY () em vez de getRawX () e getRawY (), mas isso só faz com que seja pior.
Eu não tinha certeza se getRawX () e getRawY () estavam retornando unidades de px ou unidades de dip para mim, então, esperando que ele estivesse me devolvendo unidades de px, tentei convertê-las em unidades de dip antes de atribuir os novos valores x e y para o nó, mas que apenas diminuiu o deslocamento, não o eliminou.
O que pode estar causando a diferença de onde estou tocando e onde o nó está sendo posicionado?