¿Cómo restringir el arrastrar y soltar a lo largo del eje y sólo en android?

Estoy tratando de restringir el movimiento de arrastrar y soltar a sólo el eje Y para que un usuario sólo puede tomar una vista y arrastrarlo hacia arriba o hacia abajo – no a la izquierda o derecha.

Tengo dos vistas (ids de textView y dropZone) ahora mismo. Uno (textView) tiene un oyente de tacto ajustado a él y otro (dropZone) tiene un oyente de la fricción fijado en él.

Aquí está el 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> 

El siguiente es el código de actividad:

 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 se puede ver en el código anterior, cuando un usuario arrastra textView sobre dropZone, intento convertir el color de fondo de la vista dropZone en azul. Esto funciona bien si uso crear un DragShadowBuilder en el evento de movimiento ACTION_DOWN:

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

El problema es que no puedo controlar la sombra de modo que sólo se mueve a lo largo del eje Y (vertical).

Si extraigo el código de DragShadowBuilder (las tres líneas anteriores) y agrego el código para mover la vista arrastrada en el evento de movimiento ACTION_MOVE (se ha comentado anteriormente):

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

Entonces puedo controlar el textView para mover solamente a lo largo del eje de Y. Desafortunadamente, sin un DragShadowBuilder, no puedo obtener el ACTION_DRAG_ENTERED DragEvent para disparar para activar la vista dropZone azul.

Si dejo el código de DragShadowBuilder y las cuatro líneas de código arriba, el evento de movimiento ACTION_MOVE solo se activa una vez para un arrastre; No continúa siguiendo el arrastre alrededor.

¿Alguien tiene alguna idea de lo que puedo hacer? He estado trabajando con esto por un tiempo, pero sin suerte. Incluso probé en un momento para crear una vista personalizada que amplía la clase de vista de Android, pero no puedo anular el método startDrag porque es declarado como final. Ojalá estuviera mejor en esto. 🙁

Ah ah No pude encontrar esta respuesta en ninguna parte (y mucha gente preguntaba), así que aquí está lo que hice.

La idea básica era hacer que el DragShadow invisible y pasar el movimiento del eje Y a la vista que desea "arrastrar". Así que en realidad, arrastras DragShadow, pero aparecerá al usuario que la vista arrastrable se está moviendo.

 draggableItem.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(final View view, MotionEvent motionEvent) { if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { ClipData data = ClipData.newPlainText("", ""); View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(new View(getApplicationContext())); view.startDrag(data, shadowBuilder, view, 0); return true; } else { return false; } } }); mDropZone.setOnDragListener(new View.OnDragListener() { @Override public boolean onDrag(View v, DragEvent event) { switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: ViewGroup.MarginLayoutParams lParams = (ViewGroup.MarginLayoutParams) arcMenu.getLayoutParams(); _yDelta = (int) event.getY() - lParams.topMargin; break; case DragEvent.ACTION_DRAG_LOCATION: ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) arcMenu.getLayoutParams(); layoutParams.topMargin = (int) event.getY() - _yDelta; arcMenu.setLayoutParams(layoutParams); break; case DragEvent.ACTION_DROP: // Dropped, reassign View to ViewGroup View view = (View) event.getLocalState(); // Do your drop actions here view.setVisibility(View.VISIBLE); break; default: break; } return true; } }); 

También necesitará declarar la variable _yDelta en su clase.

Espero que esto funcione para todos los gatos frescos que hay por ahí!

El siguiente código hace invisible la sombra de arrastrar pero mantiene la vista visible:

 View transparentView = new FrameLayout(getContext()); DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(transparentView); view.startDrag(data, shadowBuilder, view, 0); 

Puede cambiar el valor de y de la vista del evento de arrastrar en consecuencia:

 view.setY(event.getY()); 
  • Leer WCF REST fecha de android
  • Establecer anclaje personalizado al arrastrar una vista
  • Tamaño androide de la sombra del dragshadowbuilder
  • Cómo convertir la ubicación de toque de View en la ubicación de la pantalla HTML de WebView
  • Cómo reproducir el archivo de audio Mp3 desde el servidor
  • ¿Por qué estoy recibiendo este error "recurso esperado de tipo raw" en Android Studio?
  • OnDragListener - ¿hay alguna biblioteca de compatibilidad para niveles de Android <11?
  • Arrastrar y soltar sin eliminar del propietario
  • ¿Cómo se puede desplazar un "punto de destino" de Android drag-shadow de su "punto de contacto"?
  • Cómo cancelar View.OnDragListener en android durante la operación de arrastrar?
  • Drag'n'Drop ConcurentModificationException
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.