Drag and Drop en Android. Parte 2
Anuncio:
Finalizamos el drang and drop, en este caso vamos a examinar el código Java que hace posible la funcionalidad de la app.
Puedes ver la primera parte aquí
En primer lugar veremos el código del manifest.xml, se podría decir que es el archivo donde irá la configuración de nuestra app:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.dragdrop"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.dragdrop.DragActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Como vemos, el xml no tiene mucho que explicar, se entiende bastante bien, quizás una de las cosas que más habría que tener en cuenta sería la versión mínima de nuestro sdk, en este caso es la 16 debido a que algunas de las funciones utilizadas en el código están disponibles sólo a partir de esa versión.
Bien, ahora vamos a lo más interesante, el código Java, aunque tiene algunos comentarios en el código, explicaré algunas cosas:
package com.example.dragdrop;
import android.app.Activity;
import android.content.ClipData;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.DragEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
public class DragActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drag);
findViewById(R.id.imagen1).setOnTouchListener(new imgTouchListener());
findViewById(R.id.imagen2).setOnTouchListener(new imgTouchListener());
findViewById(R.id.left).setOnDragListener(new ContainerDragListener());
findViewById(R.id.right).setOnDragListener(new ContainerDragListener());
}
private class imgTouchListener implements OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
/*ACTION_DOWN -> A pressed gesture has started, the motion contains the initial position*/
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
ClipData data = ClipData.newPlainText("", "");
/*Creates an image that the system displays during the drag and drop operation. This is called a "drag shadow".*/
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(data, shadowBuilder, view, 0);
/*while the img is moving, the view is invisible, if we comment this line, the view 'will move' when we drop it*/
view.setVisibility(View.INVISIBLE);
return true;
} else {
return false;
}
}
}
private class ContainerDragListener implements OnDragListener {
Drawable enterShape = getResources().getDrawable(R.drawable.shape_droptarget);
Drawable normalShape = getResources().getDrawable(R.drawable.shape);
@Override
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
// do nothing
break;
case DragEvent.ACTION_DRAG_ENTERED:
/*change de background*/
v.setBackground(enterShape);
break;
case DragEvent.ACTION_DRAG_EXITED:
v.setBackground(normalShape);
break;
case DragEvent.ACTION_DROP:
// Dropped, reassign View to ViewGroup
View view = (View) event.getLocalState();
LinearLayout oldContainer = (LinearLayout) view.getParent();
oldContainer.removeView(view);
LinearLayout newContainer = (LinearLayout) v;
newContainer.addView(view);
view.setVisibility(View.VISIBLE);
break;
case DragEvent.ACTION_DRAG_ENDED:
v.setBackground(normalShape);
default:
break;
}
return true;
}
}
}
Para empezar, tenemos el método ‘onCreate’, que es llamado al crear la app, en él obtenemos los layouts y les añadimos un evento ‘onDragListener’, y obtenemos las imagenes, a las cuales les añadimos el evento ‘onTouchListener’. Sencillo.
A continuación tenemos la clase imgTouchListener, de la cual se creará una instancia para el evento añadido a la imagen, en ella, simplemente ‘escuchamos’ que la acción llevada a cabo es la de ‘pulsar’ la imagen, en ese caso llevamos a cabo el proceso de cambio de layout.
Por otra parte, la clase ‘ContainerDragListener’ es la encargada de cambiar el fondo de los layouts cuando arrastramos la imagen, en esta clase, el evento más importante sería ‘ACTION_DROP’, que se produce cuando soltamos la imagen en el nuevo layout, cuando se produzca ese evento, lo que haremos será eliminar la imagen (view) del antiguo layout y añadirla al nuevo.
Podemos ver una imagen de muestra, tomada mientras arrastramos una de las imágenes:
¿Qué os parece? A mi ya se me ocurre alguna app que implemente esto 🙂
Creo que quedó más o menos bien explicado, comenta si tienes alguna duda.
HackSaludos!
8 comentarios
Lo que necesito es cuando arrastro una imagen a otro layout, la que esta en este último se debería borrar y ponerse donde estaba la que estoy moviendo…vamos que se intercambien basicamente..y no se como hacerlo. Una ayudita? Gracias
Hola, has de implementar tu lógica en el evento ACTION_DROP, supongo que has de tener una lista de items, cuando la ejecución entre en el evento, borra el último de tu lista y añade el que llega del drag & drop. Cualquier cosa coméntanos 🙂
HackSaludos!
Buenas, en el caso de que hubiera varias imágenes para arrastrar, ¿cómo podría saber cuales están en cada layout? Gracias
Hola, si quieres saber qué imagenes tienes en cada Layout, puedes usar algo así:
int count = layout.getChildCount();
View v = null;
for(int i=0; i
Una consulta david, me gustaria consultarte que manual o libro podria leer, para a aprender a programar para android algunos libros o textos para principiantes…
Hola Federgb, Un buen texto es Android. Guía para desarrolladores.
Buenas,estoy haciendo un puzzle con este método y me ha sido de mucha utilidad, pero tengo un problema…necesito que por cada layout solo se pueda arrastrar una imagen , ahora si arrastro una imagen a un layout que ya tiene una la última se me queda debajo , mi objetivo es que si un layout ya tiene una imagen ..no pueda recoger otra…me pueden ayudar?
Hola Irene, en las líneas del case ‘DragEvent.ACTION_DROP:’ , podrías comprobar si ya hay una imagen 🙂
Si aún sigues teniendo dudas comenta 🙂