Como faço para restringir arrastar e soltar ao longo do eixo y apenas no android?

Eu estou tentando restringir o arrastar e soltar o movimento para apenas o eixo Y, de modo que um usuário só pode ter uma visão e arrastá-lo para cima ou para baixo - não para a esquerda ou para a direita.

Eu tenho dois modos de exibição (ids de textView e dropZone) agora. Um (textView) tem um ouvinte de toque definido para ele e outro (dropZone) tem um ouvinte de arrastar definido nele.

Aqui está o layout xml (activity_main.xml):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

<TextView
    android:id="@+id/textView"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="50dp"
    android:background="#FFFFFF00"
    android:text="Text Drag" />

<TextView
    android:id="@+id/dropZone"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="167dp"
    android:background="#FFFF0000"
    android:text="Drop Zone" />

</RelativeLayout>

O seguinte é o código da atividade:

package com.example.dragexperiment;

import android.app.Activity;
import android.content.ClipData;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.DragEvent;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.view.View.OnGenericMotionListener;
import android.view.View.OnTouchListener;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class MainActivity extends Activity {
TextView tv, dz, sv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv = (TextView) findViewById(R.id.textView);
        dz = (TextView) findViewById(R.id.dropZone);
        tv.setOnTouchListener(new MyTouchListener());
        dz.setOnDragListener(new MyDragListener());
    }

    private final class MyTouchListener implements OnTouchListener {
        int viewX0, viewY0,
            cY0, cY1,
            deltaCursorY;

        @Override
        public boolean onTouch(final View v,final MotionEvent event) {
              switch(event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    viewX0 = (int) v.getX();
                    viewY0 = (int) v.getY();
                    cY0 = (int) event.getRawY();
                    ClipData data = ClipData.newPlainText("", "");
                    DragShadowBuilder shadow = new View.DragShadowBuilder(v);
                    v.startDrag(data, shadow, v, 0);
                    return true;
                case MotionEvent.ACTION_MOVE:
                //  cY1 = (int) event.getRawY();
                //  deltaCursorY = cY1 - cY0;
                //  v.setX(viewX0);
                //  v.setY(viewY0 + deltaCursorY);
                    return true;
              }
              return false;
        }
    }

    class MyDragListener implements OnDragListener {

        public boolean onDrag(View v, DragEvent event) {
            switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                v.setBackgroundColor(Color.BLUE);
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                break;
            case DragEvent.ACTION_DROP:
                v.setBackgroundColor(Color.BLUE);
                break;
            case DragEvent.ACTION_DRAG_ENDED:
                break;
            default:
                break;
            }
            return true;
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

Como você pode ver no código acima, quando um usuário arrasta o textView sobre o dropZone, eu tento transformar a cor do plano de fundo da view do dropZone em azul. Isso funciona bem se eu usar criar um DragShadowBuilder no evento de movimento ACTION_DOWN:

    ClipData data = ClipData.newPlainText("", "");
    DragShadowBuilder shadow = new View.DragShadowBuilder(v);
    v.startDrag(data, shadow, v, 0);

O problema é que não consigo controlar a sombra de forma que ela apenas se mova ao longo do eixo do eixo Y (vertical).

Se eu tirar o código do DragShadowBuilder (as três linhas acima) e adicionar código para mover a vista arrastada no evento de movimento ACTION_MOVE (é comentado acima):

    cY1 = (int) event.getRawY();
    deltaCursorY = cY1 - cY0;
    v.setX(viewX0);
    v.setY(viewY0 + deltaCursorY);

Então eu posso controlar o textView para mover apenas ao longo do eixo Y. Infelizmente, sem um DragShadowBuilder, não consigo fazer com que o DragEvent ACTION_DRAG_ENTERED seja acionado para transformar a visualização dropZone em azul.

Se eu deixar tanto o código DragShadowBuilder quanto as quatro linhas de código acima, o evento de movimento ACTION_MOVE é acionado apenas uma vez para o arrasto; não continua seguindo o arrastar ao redor.

Alguém tem alguma ideia do que eu posso fazer? Eu tenho trabalhado com isso por um tempo, mas sem sorte. Eu até tentei, em um ponto, criar uma visualização personalizada que estenda a classe Android View, mas não posso substituir o método startDrag porque ele é declarado como final. Eu queria estar melhor nisso. :(

questionAnswers(2)

yourAnswerToTheQuestion