I. Drag and Drop avec Android▲
I-A. Comment faire ?▲
Depuis Android version 4.0, le drag and drop des vues est supporté. Vous enregistrez un écouteur (listener) sur la vue qui peut être source du drag et vous définissez les autres vues comme destinations potentielles (ou drop zones).
I-B. Implémentation▲
Pour faire cela, il faut enregistrer un écouteur sur la vue avec OnTouchListener ou OnLongClickListener.
Dans cette méthode, vous construisez un objet du type ClipData. Cet objet peut être utilisé pour contenir des données à passer aux vues définies comme drop zones.
L'objet DragShadowBuilder vous permet de spécifier le look de l'opération drag. En général, vous passez directement en paramètre la vue qui va être montrée pour l'opération drag.
// Assign the touch listener to your view which you want to move
findViewById
(
R.id.myimage1).setOnTouchListener
(
new
MyTouchListener
(
));
// This defines your touch listener
private
final
class
MyTouchListener implements
OnTouchListener {
public
boolean
onTouch
(
View view, MotionEvent motionEvent) {
if
(
motionEvent.getAction
(
) ==
MotionEvent.ACTION_DOWN) {
ClipData data =
ClipData.newPlainText
(
""
, ""
);
DragShadowBuilder shadowBuilder =
new
View.DragShadowBuilder
(
view);
view.startDrag
(
data, shadowBuilder, view, 0
);
view.setVisibility
(
View.INVISIBLE);
return
true
;
}
else
{
return
false
;
}
}
}
Les vues qui sont utilisées comme une zone de drop possèdent un objet OnDragListener attribué par la méthode setOnDragListener. Dans l'objet OnDragListener, vous pouvez récupérer les événements et réagir en conséquence.
findViewById
(
R.id.bottomright).setOnDragListener
(
new
MyDragListener
(
));
class
MyDragListener 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:
v.setBackgroundDrawable
(
enterShape);
break
;
case
DragEvent.ACTION_DRAG_EXITED:
v.setBackgroundDrawable
(
normalShape);
break
;
case
DragEvent.ACTION_DROP:
// Dropped, reassign View to ViewGroup
View view =
(
View) event.getLocalState
(
);
ViewGroup owner =
(
ViewGroup) view.getParent
(
);
owner.removeView
(
view);
LinearLayout container =
(
LinearLayout) v;
container.addView
(
view);
view.setVisibility
(
View.VISIBLE);
break
;
case
DragEvent.ACTION_DRAG_ENDED:
v.setBackgroundDrawable
(
normalShape);
default
:
break
;
}
return
true
;
}
}
II. Exercice▲
II-A. Création du projet▲
Créez un nouveau projet nommé de.vogella.android.draganddrop avec une activité nommée DragActivity.
II-B. Création des « drawable » XML ▲
Nous allons utiliser des objets XML « drawables » dans cet exemple.
Créez le répertoire « drawable » dans celui des ressources « res ». Créez le fichier « shape.xml » suivant dans ce répertoire :
<?xml version="1.0" encoding="UTF-8"?>
<shape
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
shape
=
"rectangle"
>
<stroke
android
:
width
=
"2dp"
android
:
color
=
"#FFFFFFFF"
/>
<gradient
android
:
angle
=
"225"
android
:
endColor
=
"#DD2ECCFA"
android
:
startColor
=
"#DD000000"
/>
<corners
android
:
bottomLeftRadius
=
"7dp"
android
:
bottomRightRadius
=
"7dp"
android
:
topLeftRadius
=
"7dp"
android
:
topRightRadius
=
"7dp"
/>
</shape>
Créez le fichier « shape_droptarget.xml » dans le répertoire « drawable » :
<?xml version="1.0" encoding="UTF-8"?>
<shape
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
shape
=
"rectangle"
>
<stroke
android
:
width
=
"2dp"
android
:
color
=
"#FFFF0000"
/>
<gradient
android
:
angle
=
"225"
android
:
endColor
=
"#DD2ECCFA"
android
:
startColor
=
"#DD000000"
/>
<corners
android
:
bottomLeftRadius
=
"7dp"
android
:
bottomRightRadius
=
"7dp"
android
:
topLeftRadius
=
"7dp"
android
:
topRightRadius
=
"7dp"
/>
</shape>
II-C. L'activité et son aspect▲
Modifiez l'aspect de votre activité en utilisant le code suivant :
<?xml version="1.0" encoding="utf-8"?>
<GridLayout
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
layout_width
=
"match_parent"
android
:
layout_height
=
"match_parent"
android
:
columnCount
=
"2"
android
:
columnWidth
=
"300dp"
android
:
orientation
=
"vertical"
android
:
rowCount
=
"2"
android
:
stretchMode
=
"columnWidth"
>
<LinearLayout
android
:
id
=
"@+id/topleft"
android
:
layout_width
=
"160dp"
android
:
layout_height
=
"200dp"
android
:
layout_column
=
"0"
android
:
layout_row
=
"0"
android
:
background
=
"@drawable/shape"
>
<ImageView
android
:
id
=
"@+id/myimage1"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
layout_column
=
"0"
android
:
layout_row
=
"0"
android
:
src
=
"@drawable/ic_launcher"
/>
</LinearLayout>
<LinearLayout
android
:
id
=
"@+id/topright"
android
:
layout_width
=
"160dp"
android
:
layout_height
=
"200dp"
android
:
layout_column
=
"1"
android
:
layout_row
=
"0"
android
:
background
=
"@drawable/shape"
>
<ImageView
android
:
id
=
"@+id/myimage2"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
layout_column
=
"0"
android
:
layout_row
=
"0"
android
:
src
=
"@drawable/ic_launcher"
/>
</LinearLayout>
<LinearLayout
android
:
id
=
"@+id/bottomleft"
android
:
layout_width
=
"160dp"
android
:
layout_height
=
"200dp"
android
:
layout_column
=
"0"
android
:
layout_row
=
"1"
android
:
background
=
"@drawable/shape"
>
<ImageView
android
:
id
=
"@+id/myimage3"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
src
=
"@drawable/ic_launcher"
/>
</LinearLayout>
<LinearLayout
android
:
id
=
"@+id/bottomright"
android
:
layout_width
=
"160dp"
android
:
layout_height
=
"200dp"
android
:
layout_column
=
"1"
android
:
layout_row
=
"1"
android
:
background
=
"@drawable/shape"
>
<ImageView
android
:
id
=
"@+id/myimage4"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
layout_column
=
"0"
android
:
layout_row
=
"0"
android
:
src
=
"@drawable/ic_launcher"
/>
</LinearLayout>
</GridLayout>
Modifiez le source de votre activité en utilisant le code suivant :
package
de.vogella.android.draganddrop;
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 {
/** Called when the activity is first created. */
@Override
public
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
setContentView
(
R.layout.main);
findViewById
(
R.id.myimage1).setOnTouchListener
(
new
MyTouchListener
(
));
findViewById
(
R.id.myimage2).setOnTouchListener
(
new
MyTouchListener
(
));
findViewById
(
R.id.myimage3).setOnTouchListener
(
new
MyTouchListener
(
));
findViewById
(
R.id.myimage4).setOnTouchListener
(
new
MyTouchListener
(
));
findViewById
(
R.id.topleft).setOnDragListener
(
new
MyDragListener
(
));
findViewById
(
R.id.topright).setOnDragListener
(
new
MyDragListener
(
));
findViewById
(
R.id.bottomleft).setOnDragListener
(
new
MyDragListener
(
));
findViewById
(
R.id.bottomright).setOnDragListener
(
new
MyDragListener
(
));
}
private
final
class
MyTouchListener implements
OnTouchListener {
public
boolean
onTouch
(
View view, MotionEvent motionEvent) {
if
(
motionEvent.getAction
(
) ==
MotionEvent.ACTION_DOWN) {
ClipData data =
ClipData.newPlainText
(
""
, ""
);
DragShadowBuilder shadowBuilder =
new
View.DragShadowBuilder
(
view);
view.startDrag
(
data, shadowBuilder, view, 0
);
view.setVisibility
(
View.INVISIBLE);
return
true
;
}
else
{
return
false
;
}
}
}
class
MyDragListener 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:
v.setBackgroundDrawable
(
enterShape);
break
;
case
DragEvent.ACTION_DRAG_EXITED:
v.setBackgroundDrawable
(
normalShape);
break
;
case
DragEvent.ACTION_DROP:
// Dropped, reassign View to ViewGroup
View view =
(
View) event.getLocalState
(
);
ViewGroup owner =
(
ViewGroup) view.getParent
(
);
owner.removeView
(
view);
LinearLayout container =
(
LinearLayout) v;
container.addView
(
view);
view.setVisibility
(
View.VISIBLE);
break
;
case
DragEvent.ACTION_DRAG_ENDED:
v.setBackgroundDrawable
(
normalShape);
default
:
break
;
}
return
true
;
}
}
}
Si vous lancez votre activité, vous devrez être capable de faire un drag des images vers un autre conteneur.
III. Quelques liens▲
IV. Remerciements▲
Nous remercions l'auteur, Lars Vogel, de nous avoir aimablement autorisés à publier son article. Cet article est une traduction autorisée dont le texte original peut être trouvé sur vogella.com. Nous remercions aussi ram-0000 pour sa traduction, Feanorin pour sa relecture technique ainsi que milkoseck pour sa relecture orthographique.