¿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.
- ¿Cómo obtener el comportamiento de pantalla de inicio de arrastrar a bin, en mi propia aplicación?
- Cómo hacer Drag & Drop Button en Android
- Cómo crear una sombra de arrastre personalizada?
- Cómo arrastrar varias vistas de botón en java
- Android: realizar arrastrar y soltar mediante programación
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. 🙁
- Hacer un lienzo transparente no transparente (tratando de sustituir el aspecto predeterminado de DragShadow con arrastrar y soltar en Android)
- Java convertir la marca de tiempo UTC a DateTime local
- ¿Cómo obtener la vista mientras arrastrar y soltar en android?
- Cómo obtener las coordenadas X, Y correctas de un DragEvent.ACTION_DROP
- Cómo escribir un InputStream potencialmente enorme para el archivo?
- ¿Cómo obtener el formato de fecha seleccionado por el usuario en Android?
- Android: Problema de arrastrar y soltar
- Arrastrar y soltar con onDraglistener animar para volver a la posición original si no se deja caer en el objetivo
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());
- No se puede realizar la operación porque no hay ninguna transacción actual al insertar en la base de datos
- Android-GCM: ¿Cómo cuidar a un usuario desconectado?