Sie können Ihren Drag-and-drop-Prozess in Ansichten implementieren, indem Sie auf Ereignisse reagieren. die einen Drag-Start und eine Reaktion und aufwendende Drop-Ereignisse auslösen können.
Drag-Vorgang starten
Der Nutzer beginnt das Ziehen mit einer Geste, in der Regel durch Berühren oder Klicken und ein Element halten, das es ziehen möchte.
Um dies in einem View
zu verarbeiten, erstellen Sie einen
ClipData
-Objekt und
ClipData.Item
-Objekt für
die zu verschieben sind. Geben Sie im Rahmen der ClipData
Metadaten an, die
in einem
Objekt ClipDescription
innerhalb von ClipData
. Für einen Drag-and-drop-Vorgang, der nicht
Datenbewegungen ausführen, möchten Sie möglicherweise null
anstelle eines tatsächlichen Objekts verwenden.
Dieses Code-Snippet zeigt beispielsweise, wie auf Berührungen und Hold
Geste für ein ImageView
durch Erstellen eines ClipData
-Objekts, das die
Tag (oder Label) eines ImageView
:
Kotlin
// Create a string for the ImageView label. val IMAGEVIEW_TAG = "icon bitmap" ... val imageView = ImageView(context).apply { // Set the bitmap for the ImageView from an icon bitmap defined elsewhere. setImageBitmap(iconBitmap) tag = IMAGEVIEW_TAG setOnLongClickListener { v -> // Create a new ClipData. This is done in two steps to provide // clarity. The convenience method ClipData.newPlainText() can // create a plain text ClipData in one step. // Create a new ClipData.Item from the ImageView object's tag. val item = ClipData.Item(v.tag as? CharSequence) // Create a new ClipData using the tag as a label, the plain text // MIME type, and the already-created item. This creates a new // ClipDescription object within the ClipData and sets its MIME type // to "text/plain". val dragData = ClipData( v.tag as? CharSequence, arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN), item) // Instantiate the drag shadow builder. We use this imageView object // to create the default builder. val myShadow = View.DragShadowBuilder(view: this) // Start the drag. v.startDragAndDrop(dragData, // The data to be dragged. myShadow, // The drag shadow builder. null, // No need to use local data. 0 // Flags. Not currently used, set to 0. ) // Indicate that the long-click is handled. true } }
Java
// Create a string for the ImageView label. private static final String IMAGEVIEW_TAG = "icon bitmap"; ... // Create a new ImageView. ImageView imageView = new ImageView(context); // Set the bitmap for the ImageView from an icon bitmap defined elsewhere. imageView.setImageBitmap(iconBitmap); // Set the tag. imageView.setTag(IMAGEVIEW_TAG); // Set a long-click listener for the ImageView using an anonymous listener // object that implements the OnLongClickListener interface. imageView.setOnLongClickListener( v -> { // Create a new ClipData. This is done in two steps to provide clarity. The // convenience method ClipData.newPlainText() can create a plain text // ClipData in one step. // Create a new ClipData.Item from the ImageView object's tag. ClipData.Item item = new ClipData.Item((CharSequence) v.getTag()); // Create a new ClipData using the tag as a label, the plain text MIME type, // and the already-created item. This creates a new ClipDescription object // within the ClipData and sets its MIME type to "text/plain". ClipData dragData = new ClipData( (CharSequence) v.getTag(), new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN }, item); // Instantiate the drag shadow builder. We use this imageView object // to create the default builder. View.DragShadowBuilder myShadow = new View.DragShadowBuilder(imageView); // Start the drag. v.startDragAndDrop(dragData, // The data to be dragged. myShadow, // The drag shadow builder. null, // No need to use local data. 0 // Flags. Not currently used, set to 0. ); // Indicate that the long-click is handled. return true; });
Auf Ziehstart reagieren
Während des Drag-Vorgangs löst das System Drag-Ereignisse an das Drag-Ereignis aus
Listener der View
-Objekte im aktuellen Layout. Die Zuhörer reagieren
DragEvent.getAction()
wird aufgerufen, um den Aktionstyp abzurufen. Zu Beginn eines Drag
Diese Methode gibt ACTION_DRAG_STARTED
zurück.
Als Reaktion auf ein Ereignis mit dem Aktionstyp ACTION_DRAG_STARTED
wird ein Drag-Ereignis
muss der Listener Folgendes ausführen:
Anruf
DragEvent.getClipDescription()
und verwenden Sie die MIME-Typ-Methoden in der zurückgegebenenClipDescription
, um Gibt an, ob der Listener die verschobenen Daten akzeptieren kann.Wenn der Drag-and-drop-Vorgang nicht Datenbewegungen repräsentiert, könnte dies unnötig sein.
Wenn der Drag-Event-Listener einen Drop akzeptieren kann, muss er
true
zurückgeben. um weiterhin Ziehereignisse an den Listener zu senden. Wenn der Listener kann einen Drop nicht akzeptieren, der Listener mussfalse
zurückgeben und das System stoppt Drag-Events an den Listener senden, bis das SystemACTION_DRAG_ENDED
, um den Drag-and-drop-Vorgang abzuschließen.
Für ein ACTION_DRAG_STARTED
-Ereignis sind die folgenden DragEvent
-Methoden nicht verfügbar
gültig: getClipData()
,
getX()
,
getY()
und
getResult()
.
Ereignisse beim Ziehen verarbeiten
Während der Drag-Aktion ziehen Sie Event-Listener, die true
als Reaktion auf
erhält das Drag-Event ACTION_DRAG_STARTED
weiterhin Drag-Events. Typen
Drag-Ereignisse, die ein Listener während des Ziehvorgangs empfängt, hängt von der Position des
Drag-Shadow und die Sichtbarkeit von View
des Listeners. Listener verwenden die Ziehbewegung
, um zu entscheiden, ob das Aussehen von View
geändert werden muss.
Während des Ziehvorgangs gibt DragEvent.getAction()
einen von drei Werten zurück:
ACTION_DRAG_ENTERED
: Der Listener empfängt diesen Ereignisaktionstyp, wenn der Touchpoint – der auf den Bildschirm unter dem Finger oder der Maus der Nutzenden – Begrenzungsrahmen derView
des Listeners.ACTION_DRAG_LOCATION
: Sobald der Listener einACTION_DRAG_ENTERED
-Ereignis empfängt, erhält er ein neuesACTION_DRAG_LOCATION
-Ereignis, wenn sich der Touchpoint bis zum erhält einACTION_DRAG_EXITED
-Ereignis. Die MethodengetX()
undgetY()
die X- und Y-Koordinaten des Berührungspunkts zurückgeben.ACTION_DRAG_EXITED
: wird dieser Ereignisaktionstyp an einen Listener gesendet, der zuvorACTION_DRAG_ENTERED
. Das Ereignis wird gesendet, wenn der Drag-Schatten-Touchpoint bewegt sich vom Begrenzungsrahmen desView
-Objekts des Listeners nach außerhalb des Begrenzungsrahmen.
Der Drag-Event-Listener muss auf keinen dieser Aktionstypen reagieren. Wenn wenn der Listener einen Wert an das System zurückgibt, wird dieser ignoriert.
Im Folgenden finden Sie einige Richtlinien für die Reaktion auf die einzelnen Aktionstypen:
- Als Antwort auf
ACTION_DRAG_ENTERED
oderACTION_DRAG_LOCATION
wird der Listener kann die Darstellung desView
ändern, um anzugeben, dass es sich bei der Ansicht um eine potenzielles Drop-Ziel. - Ein Ereignis mit dem Aktionstyp
ACTION_DRAG_LOCATION
enthält gültige Daten fürgetX()
undgetY()
für die Position des Berührungspunkts. Die Listener kann anhand dieser Informationen die Darstellung vonView
am um die genaue Position zu bestimmen, an der der Nutzer Inhalte. - Als Antwort auf
ACTION_DRAG_EXITED
muss der Listener alle Darstellungsweisen zurücksetzen als Reaktion aufACTION_DRAG_ENTERED
oderACTION_DRAG_LOCATION
Dadurch wird dem Nutzer mitgeteilt, dass dieView
nicht ein bevorstehendes Drop-Ziel länger ist.
Auf einen Rückgang reagieren
Wenn der Nutzer den Drag-Schatten über View
loslässt und den View
zuvor
gibt an, dass es Drag-and-drop-Inhalte akzeptieren kann, sendet das System eine
Ziehen Sie das Ereignis per Drag-and-drop in das Feld View
mit dem Aktionstyp ACTION_DROP
.
Der Drag-Event-Listener muss Folgendes tun:
Rufen Sie
getClipData()
auf, um dasClipData
-Objekt abzurufen, das ursprünglich im Aufruf vonstartDragAndDrop()
und verarbeiten die Daten. Wenn per Drag-and-drop keine Daten dargestellt werden zu bewegen, ist das unnötig.Gibt den booleschen Wert
true
zurück, um anzugeben, dass der Drop erfolgreich verarbeitet wurde. oderfalse
, wenn nicht. Der zurückgegebene Wert wird zum Wert, der vongetResult()
für das letztendlicheACTION_DRAG_ENDED
-Ereignis. Wenn das System keinACTION_DROP
-Ereignis sendet (der vongetResult()
zurückgegebene Wert) für einACTION_DRAG_ENDED
-Ereignis:false
.
Bei einem ACTION_DROP
-Ereignis verwenden getX()
und getY()
das Koordinatensystem von
View
, die den Rückgang erhält, um die X- und Y-Position des
den Touchpoint zum Zeitpunkt des Absturzes erreicht hat.
Der Nutzer kann den Drag-Schatten über einem View
-Element loslassen, dessen Drag-Event
keine Drag-Events, leere Bereiche der App-Benutzeroberfläche oder sogar
außerhalb Ihrer App platziert, sendet Android kein Ereignis mit
geben Sie ACTION_DROP
ein und es wird nur ein ACTION_DRAG_ENDED
-Ereignis gesendet.
Auf Ziehende reagieren
Sobald der Nutzer den Drag-Schatten loslässt, sendet das System eine Drag-and-drop-Funktion
-Ereignis mit dem Aktionstyp ACTION_DRAG_ENDED
an alle Drag-Event-Listener
in Ihrer Anwendung. Dies bedeutet, dass der Drag-Vorgang abgeschlossen ist.
Jeder Drag-Event-Listener muss Folgendes tun:
- Wenn der Listener während des Vorgangs seine Darstellung ändert, sollte er zurückgesetzt werden. wieder in die Standardansicht zurück, damit der Nutzer sieht, abgeschlossen ist.
- Der Listener kann optional
getResult()
aufrufen, um weitere Informationen zum . Wenn ein Listenertrue
als Antwort auf ein Aktionsereignis zurückgibt TypACTION_DROP
, dann gibtgetResult()
den booleschen Werttrue
zurück. In allen anderen gibtgetResult()
den booleschen Wertfalse
zurück, auch wenn das System sendet keinACTION_DROP
-Ereignis. - Um anzugeben, dass der Drop-Vorgang erfolgreich abgeschlossen wurde,
sollte den booleschen Wert
true
an das System zurückgeben. Wenn Siefalse
nicht zurückgeben, geschieht Folgendes: Ein visueller Hinweis, dass der Schlagschatten zu seiner Quelle zurückkehrt, könnte darauf hinweisen, dem Nutzer, dass der Vorgang fehlgeschlagen ist.
Auf Drag-Events reagieren: Ein Beispiel
Alle Drag-Ereignisse werden von Ihrer Drag-Event-Methode oder Ihrem Listener empfangen. Die Das folgende Code-Snippet ist ein Beispiel für die Reaktion auf Drag-Events:
Kotlin
val imageView = ImageView(this) // Set the drag event listener for the View. imageView.setOnDragListener { v, e -> // Handle each of the expected events. when (e.action) { DragEvent.ACTION_DRAG_STARTED -> { // Determine whether this View can accept the dragged data. if (e.clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { // As an example, apply a blue color tint to the View to // indicate that it can accept data. (v as? ImageView)?.setColorFilter(Color.BLUE) // Invalidate the view to force a redraw in the new tint. v.invalidate() // Return true to indicate that the View can accept the dragged // data. true } else { // Return false to indicate that, during the current drag and // drop operation, this View doesn't receive events again until // ACTION_DRAG_ENDED is sent. false } } DragEvent.ACTION_DRAG_ENTERED -> { // Apply a green tint to the View. (v as? ImageView)?.setColorFilter(Color.GREEN) // Invalidate the view to force a redraw in the new tint. v.invalidate() // Return true. The value is ignored. true } DragEvent.ACTION_DRAG_LOCATION -> // Ignore the event. true DragEvent.ACTION_DRAG_EXITED -> { // Reset the color tint to blue. (v as? ImageView)?.setColorFilter(Color.BLUE) // Invalidate the view to force a redraw in the new tint. v.invalidate() // Return true. The value is ignored. true } DragEvent.ACTION_DROP -> { // Get the item containing the dragged data. val item: ClipData.Item = e.clipData.getItemAt(0) // Get the text data from the item. val dragData = item.text // Display a message containing the dragged data. Toast.makeText(this, "Dragged data is $dragData", Toast.LENGTH_LONG).show() // Turn off color tints. (v as? ImageView)?.clearColorFilter() // Invalidate the view to force a redraw. v.invalidate() // Return true. DragEvent.getResult() returns true. true } DragEvent.ACTION_DRAG_ENDED -> { // Turn off color tinting. (v as? ImageView)?.clearColorFilter() // Invalidate the view to force a redraw. v.invalidate() // Do a getResult() and display what happens. when(e.result) { true -> Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG) else -> Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG) }.show() // Return true. The value is ignored. true } else -> { // An unknown action type is received. Log.e("DragDrop Example", "Unknown action type received by View.OnDragListener.") false } } }
Java
View imageView = new ImageView(this); // Set the drag event listener for the View. imageView.setOnDragListener( (v, e) -> { // Handle each of the expected events. switch(e.getAction()) { case DragEvent.ACTION_DRAG_STARTED: // Determine whether this View can accept the dragged data. if (e.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { // As an example, apply a blue color tint to the View to // indicate that it can accept data. ((ImageView)v).setColorFilter(Color.BLUE); // Invalidate the view to force a redraw in the new tint. v.invalidate(); // Return true to indicate that the View can accept the dragged // data. return true; } // Return false to indicate that, during the current drag-and-drop // operation, this View doesn't receive events again until // ACTION_DRAG_ENDED is sent. return false; case DragEvent.ACTION_DRAG_ENTERED: // Apply a green tint to the View. ((ImageView)v).setColorFilter(Color.GREEN); // Invalidate the view to force a redraw in the new tint. v.invalidate(); // Return true. The value is ignored. return true; case DragEvent.ACTION_DRAG_LOCATION: // Ignore the event. return true; case DragEvent.ACTION_DRAG_EXITED: // Reset the color tint to blue. ((ImageView)v).setColorFilter(Color.BLUE); // Invalidate the view to force a redraw in the new tint. v.invalidate(); // Return true. The value is ignored. return true; case DragEvent.ACTION_DROP: // Get the item containing the dragged data. ClipData.Item item = e.getClipData().getItemAt(0); // Get the text data from the item. CharSequence dragData = item.getText(); // Display a message containing the dragged data. Toast.makeText(this, "Dragged data is " + dragData, Toast.LENGTH_LONG).show(); // Turn off color tints. ((ImageView)v).clearColorFilter(); // Invalidate the view to force a redraw. v.invalidate(); // Return true. DragEvent.getResult() returns true. return true; case DragEvent.ACTION_DRAG_ENDED: // Turn off color tinting. ((ImageView)v).clearColorFilter(); // Invalidate the view to force a redraw. v.invalidate(); // Do a getResult() and displays what happens. if (e.getResult()) { Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG).show(); } // Return true. The value is ignored. return true; // An unknown action type is received. default: Log.e("DragDrop Example","Unknown action type received by View.OnDragListener."); break; } return false; });
Drag-Schatten anpassen
Sie können eine benutzerdefinierte myDragShadowBuilder
definieren, indem Sie die Methoden in
View.DragShadowBuilder
. Mit dem folgenden Code-Snippet wird eine kleine,
rechteckiger, grauer Drag-Schatten für TextView
:
Kotlin
private class MyDragShadowBuilder(view: View) : View.DragShadowBuilder(view) { private val shadow = ColorDrawable(Color.LTGRAY) // Define a callback that sends the drag shadow dimensions and touch point // back to the system. override fun onProvideShadowMetrics(size: Point, touch: Point) { // Set the width of the shadow to half the width of the original // View. val width: Int = view.width / 2 // Set the height of the shadow to half the height of the original // View. val height: Int = view.height / 2 // The drag shadow is a ColorDrawable. Set its dimensions to // be the same as the Canvas that the system provides. As a result, // the drag shadow fills the Canvas. shadow.setBounds(0, 0, width, height) // Set the size parameter's width and height values. These get back // to the system through the size parameter. size.set(width, height) // Set the touch point's position to be in the middle of the drag // shadow. touch.set(width / 2, height / 2) } // Define a callback that draws the drag shadow in a Canvas that the system // constructs from the dimensions passed to onProvideShadowMetrics(). override fun onDrawShadow(canvas: Canvas) { // Draw the ColorDrawable on the Canvas passed in from the system. shadow.draw(canvas) } }
Java
private static class MyDragShadowBuilder extends View.DragShadowBuilder { // The drag shadow image, defined as a drawable object. private static Drawable shadow; // Constructor. public MyDragShadowBuilder(View view) { // Store the View parameter. super(view); // Create a draggable image that fills the Canvas provided by the // system. shadow = new ColorDrawable(Color.LTGRAY); } // Define a callback that sends the drag shadow dimensions and touch point // back to the system. @Override public void onProvideShadowMetrics (Point size, Point touch) { // Define local variables. int width, height; // Set the width of the shadow to half the width of the original // View. width = getView().getWidth() / 2; // Set the height of the shadow to half the height of the original // View. height = getView().getHeight() / 2; // The drag shadow is a ColorDrawable. Set its dimensions to // be the same as the Canvas that the system provides. As a result, // the drag shadow fills the Canvas. shadow.setBounds(0, 0, width, height); // Set the size parameter's width and height values. These get back // to the system through the size parameter. size.set(width, height); // Set the touch point's position to be in the middle of the drag // shadow. touch.set(width / 2, height / 2); } // Define a callback that draws the drag shadow in a Canvas that the system // constructs from the dimensions passed to onProvideShadowMetrics(). @Override public void onDrawShadow(Canvas canvas) { // Draw the ColorDrawable on the Canvas passed in from the system. shadow.draw(canvas); } }