Wichtige Konzepte

In den folgenden Abschnitten werden einige Schlüsselkonzepte für den Drag-and-drop-Prozess erläutert.

Drag-and-drop-Prozess

Der Drag-and-drop-Prozess umfasst vier Schritte oder Zustände: gestartet, fortgesetzt, entfernt und beendet.

Gestartet

Als Reaktion auf die Drag-Geste eines Nutzers ruft Ihre Anwendung startDragAndDrop() auf, um das System anzuweisen, einen Drag-and-drop-Vorgang zu starten. Die Argumente der Methode liefern Folgendes:

  • Die Daten, die gezogen werden sollen.
  • Ein Callback zum Zeichnen des Ziehschattens
  • Metadaten, die die gezogenen Daten beschreiben
  • Das System antwortet, indem es deine Anwendung zurückruft, um einen Drag-Schatten zu erhalten. Das System zeigt dann den Ziehschatten auf dem Gerät an.
  • Als Nächstes sendet das System ein Drag-Ereignis mit dem Aktionstyp ACTION_DRAG_STARTED an den Drag-Event-Listener aller View-Objekte im aktuellen Layout. Damit weiterhin Drag-Ereignisse empfangen werden, einschließlich eines möglichen Drop-Ereignisses, muss der Drag-Event-Listener true zurückgeben. Dadurch wird der Listener beim System registriert. Nur registrierte Listener empfangen weiterhin Drag-Ereignisse. An dieser Stelle können Listener auch die Darstellung ihres Drop-Ziel-View-Objekts ändern, um anzuzeigen, dass die Ansicht ein Drop-Ereignis akzeptieren kann.
  • Wenn der Drag-Event-Listener false zurückgibt, empfängt er keine Drag-Ereignisse für den aktuellen Vorgang, bis das System ein Drag-Ereignis mit dem Aktionstyp ACTION_DRAG_ENDED sendet. Durch die Rückgabe von false teilt der Listener dem System mit, dass er kein Interesse am Drag-and-drop-Vorgang hat und die per Drag-and-drop eingefügten Daten nicht akzeptieren möchte.
Wird fortgesetzt
Der Nutzer zieht den Zug weiter. Wenn sich der Ziehschatten den Markierungsrahmen eines Ablegeziels überschneidet, sendet das System ein oder mehrere Drag-Ereignisse an den Drag-Event-Listener des Ziels. Der Listener kann die Darstellung des Drop-Ziel-View als Reaktion auf das Ereignis ändern. Wenn das Ereignis beispielsweise anzeigt, dass der Ziehschatten in den Begrenzungsrahmen des Drop-Ziels (Aktionstyp ACTION_DRAG_ENTERED) gelangt, kann der Listener View markieren, um zu reagieren.
Abgebrochen
Der Nutzer lässt den Ziehschatten innerhalb des Begrenzungsrahmens eines Drop-Ziels los. Das System sendet ein Drag-Ereignis mit dem Aktionstyp ACTION_DROP an den Listener des Ablageziels. Das Drag-Ereignisobjekt enthält die Daten, die im Aufruf von startDragAndDrop(), der den Vorgang startet, an das System übergeben wird. Es wird erwartet, dass der Listener den booleschen Wert true an das System zurückgibt, wenn der Listener die gelöschten Daten erfolgreich verarbeitet hat. Dieser Schritt erfolgt nur, wenn der Nutzer den Drag-Schatten in das Begrenzungsrahmen von View bewegt, dessen Listener für den Empfang von Drag-Ereignissen (Drop-Ziel) registriert ist. Wenn der Nutzer den Ziehschatten in einer anderen Situation loslässt, wird kein ACTION_DROP-Drag-Ereignis gesendet.
Beendet

Nachdem der Nutzer den Ziehschatten loslässt und das System

Wenn ein Drag-Ereignis mit dem Aktionstyp ACTION_DROP ausgeführt wird, sendet das System bei Bedarf ein Drag-Ereignis mit dem Aktionstyp ACTION_DRAG_ENDED, um anzugeben, dass der Drag-and-drop-Vorgang beendet ist. Dies geschieht unabhängig davon, an welcher Stelle der Ziehschatten loslässt. Das Ereignis wird an jeden Listener gesendet, der für den Empfang von Drag-Ereignissen registriert ist, selbst wenn der Listener auch das Ereignis ACTION_DROP empfängt.

Jeder dieser Schritte wird im Abschnitt Drag-and-drop-Vorgang ausführlicher beschrieben.

Drag-Ereignisse

Das System sendet ein Drag-Ereignis in Form eines DragEvent-Objekts, das einen Aktionstyp enthält, der beschreibt, was beim Drag-and-drop-Prozess passiert. Je nach Aktionstyp kann das Objekt auch andere Daten enthalten.

Drag-Event-Listener empfangen das DragEvent-Objekt. Um den Aktionstyp zu erhalten, rufen die Listener DragEvent.getAction() auf. In der Klasse DragEvent gibt es sechs mögliche Werte, die durch Konstanten definiert und in Tabelle 1 beschrieben werden:

Tabelle 1 DragEvent-Aktionstypen

Aktionstyp Bedeutung
ACTION_DRAG_STARTED Die Anwendung ruft startDragAndDrop() auf und ruft einen Ziehschatten ab. Wenn der Listener für diesen Vorgang weiterhin Drag-Ereignisse empfangen möchte, muss er den booleschen Wert true an das System zurückgeben.
ACTION_DRAG_ENTERED Der Ziehschatten befindet sich im Begrenzungsrahmen des View des Ziehereignis-Listeners. Dies ist der erste Ereignisaktionstyp, den der Listener empfängt, wenn der Ziehschatten den Begrenzungsrahmen erreicht.
ACTION_DRAG_LOCATION Nach einem ACTION_DRAG_ENTERED-Ereignis befindet sich der Ziehschatten immer noch innerhalb des Begrenzungsrahmens des View des Ziehereignis-Listeners.
ACTION_DRAG_EXITED Nach einem ACTION_DRAG_ENTERED- und mindestens einem ACTION_DRAG_LOCATION-Ereignis bewegt sich der Ziehschatten aus dem Begrenzungsrahmen des Listener-View des Drag-Event-Listeners hinaus.
ACTION_DROP Der Ziehschatten wird über dem View des Drag-Event-Listeners wieder bewegt. Dieser Aktionstyp wird nur dann an den Listener eines View-Objekts gesendet, wenn der Listener als Antwort auf das Drag-Ereignis ACTION_DRAG_STARTED den booleschen Wert true zurückgibt. Dieser Aktionstyp wird nicht gesendet, wenn der Nutzer den Ziehschatten über einem View loslässt, dessen Listener nicht registriert ist, oder wenn der Nutzer den Ziehschatten über etwas loslässt, das nicht Teil des aktuellen Layouts ist.

Der Listener gibt den booleschen Wert true zurück, wenn er den Vorgang erfolgreich verarbeitet hat. Andernfalls muss false zurückgegeben werden.

ACTION_DRAG_ENDED Das System beendet den Drag-and-drop-Vorgang. Diesem Aktionstyp geht nicht unbedingt ein ACTION_DROP-Ereignis voraus. Wenn das System eine ACTION_DROP sendet, bedeutet der Empfang des Aktionstyps ACTION_DRAG_ENDED nicht, dass der Löschvorgang erfolgreich war. Der Listener muss getResult() aufrufen, wie in Tabelle 2 gezeigt, um den Wert zu erhalten, der als Antwort auf ACTION_DROP zurückgegeben wird. Wenn kein ACTION_DROP-Ereignis gesendet wird, gibt getResult() den Wert false zurück.

Das DragEvent-Objekt enthält auch die Daten und Metadaten, die Ihre Anwendung dem System im Aufruf von startDragAndDrop() bereitstellt. Einige der Daten sind nur für bestimmte Aktionstypen gültig, wie in Tabelle 2 zusammengefasst. Weitere Informationen zu Ereignissen und den zugehörigen Daten finden Sie im Abschnitt Drag-and-drop-Vorgang.

Tabelle 2 Gültige DragEvent-Daten nach Aktionstyp

getAction()
Wert
getClipDescription()
Wert
getLocalState()
Wert
getX()
Wert
getY()
Wert
getClipData()
Wert
getResult()
Wert
ACTION_DRAG_STARTED ✓ ✓        
ACTION_DRAG_ENTERED ✓ ✓        
ACTION_DRAG_LOCATION ✓ ✓ ✓ ✓    
ACTION_DRAG_EXITED ✓ ✓        
ACTION_DROP ✓ ✓ ✓ ✓ ✓  
ACTION_DRAG_ENDED   ✓       ✓

Die DragEvent-Methoden getAction(), describeContents(), writeToParcel() und toString() geben immer gültige Daten zurück.

Wenn eine Methode für einen bestimmten Aktionstyp keine gültigen Daten enthält, gibt sie je nach Ergebnistyp null oder 0 zurück.

Schatten ziehen

Während eines Drag-and-drop-Vorgangs zeigt das System ein Bild an, das der Nutzer anzieht. Zur Datenbewegung stellt dieses Bild die Daten dar, die gezogen werden. Bei anderen Vorgängen stellt das Bild einen Teil des Drag-Vorgangs dar.

Dieses Bild wird als Drag-Schatten bezeichnet. Sie erstellen ihn mit Methoden, die Sie für ein View.DragShadowBuilder-Objekt deklarieren. Sie übergeben den Builder an das System, wenn Sie einen Drag-and-drop-Vorgang mit startDragAndDrop() starten. Im Rahmen der Antwort auf startDragAndDrop() ruft das System die Callback-Methoden auf, die Sie in View.DragShadowBuilder definieren, um einen Ziehschatten zu erhalten.

Die View.DragShadowBuilder-Klasse hat zwei Konstruktoren:

View.DragShadowBuilder(View)

Dieser Konstruktor akzeptiert alle View-Objekte Ihrer Anwendung. Der Konstruktor speichert das View-Objekt im View.DragShadowBuilder-Objekt, sodass die Callbacks darauf zugreifen können, um den Ziehschatten zu erstellen. Die Ansicht muss kein View sein, das der Nutzer zum Starten des Drag-Vorgangs auswählt.

Wenn Sie diesen Konstruktor verwenden, müssen Sie View.DragShadowBuilder nicht erweitern oder seine Methoden überschreiben. Standardmäßig wird ein Ziehschatten zurückgegeben, der genauso aussieht wie der View, den Sie als Argument übergeben. Er befindet sich in der Mitte der Stelle, an der der Nutzer den Bildschirm berührt.

View.DragShadowBuilder()

Wenn Sie diesen Konstruktor verwenden, ist im Objekt View.DragShadowBuilder kein View-Objekt verfügbar. Das Feld ist auf null festgelegt. Sie müssen View.DragShadowBuilder erweitern und die zugehörigen Methoden überschreiben. Andernfalls erhalten Sie einen unsichtbaren Ziehschatten. Das System gibt keinen Fehler aus.

Die Klasse View.DragShadowBuilder hat zwei Methoden, die zusammen den Ziehschatten erstellen:

onProvideShadowMetrics()

Das System ruft diese Methode sofort nach dem Aufruf von startDragAndDrop() auf. Verwenden Sie diese Methode, um die Abmessungen und den Touchpoint des Ziehschattens an das System zu senden. Die Methode hat zwei Parameter:

outShadowSize: Ein Point-Objekt. Die Breite des Ziehschattens wird in x und seine Höhe in y eingegeben.

outShadowTouchPoint: Ein Point-Objekt. Der Touchpoint ist die Stelle innerhalb des Ziehschattens, die sich während des Ziehens unter dem Finger des Nutzers befinden muss. Ihre X-Position geht in x und die Y-Position in y.

onDrawShadow()

Sofort nach dem Aufruf von onProvideShadowMetrics() ruft das System onDrawShadow() auf, um den Ziehschatten zu erstellen. Die Methode hat ein einzelnes Argument, ein Canvas-Objekt, das vom System aus den Parametern erstellt wird, die Sie in onProvideShadowMetrics() angeben. Die Methode zeichnet den Ziehschatten auf dem angegebenen Canvas.

Halten Sie den Ziehschatten klein, um die Leistung zu verbessern. Für ein einzelnes Element können Sie ein Symbol verwenden. Bei einer Auswahl mit mehreren Elementen sollten Sie Symbole in einem Stapel statt ganzer Bilder verwenden, die über den Bildschirm verstreut sind.

Drag-Event-Listener und Callback-Methoden

Ein View empfängt Drag-Ereignisse mit einem Drag-Event-Listener, der View.OnDragListener implementiert, oder mit der onDragEvent()-Callback-Methode der Ansicht. Wenn das System die Methode oder den Listener aufruft, wird das Argument DragEvent bereitgestellt.

In den meisten Fällen empfiehlt sich die Verwendung eines Listeners der Verwendung der Callback-Methode. Wenn Sie UIs entwerfen, erstellen Sie normalerweise keine abgeleiteten Klassen von View-Klassen. Wenn Sie jedoch die Callback-Methode verwenden, müssen Sie Unterklassen erstellen, um die Methode zu überschreiben. Im Vergleich dazu können Sie eine Listener-Klasse implementieren und dann mit mehreren verschiedenen View-Objekten verwenden. Du kannst es auch als anonyme Inline-Klasse oder als Lambda-Ausdruck implementieren. Rufen Sie setOnDragListener() auf, um den Listener für ein View-Objekt festzulegen.

Alternativ können Sie die Standardimplementierung von onDragEvent() ändern, ohne die Methode zu überschreiben. Legen Sie ein OnReceiveContentListener für eine Ansicht fest. Weitere Informationen finden Sie unter setOnReceiveContentListener(). Die Methode onDragEvent() führt dann standardmäßig folgende Schritte aus:

  • Gibt „true“ als Antwort auf den Aufruf von startDragAndDrop() zurück.
  • Ruft performReceiveContent() auf, wenn die Drag-and-drop-Daten in die Ansicht verschoben werden. Die Daten werden als ContentInfo-Objekt an die Methode übergeben. Die Methode ruft die OnReceiveContentListener auf.

  • Gibt „true“ zurück, wenn die Drag-and-drop-Daten in der Ansicht abgelegt werden und OnReceiveContentListener einen Teil der Inhalte aufnimmt.

Definieren Sie die OnReceiveContentListener für die Verarbeitung der Daten speziell für Ihre Anwendung. Verwenden Sie für die Abwärtskompatibilität bis hin zum API-Level 24 die Jetpack-Version von OnReceiveContentListener.

Sie können einen Drag-Event-Listener und eine Callback-Methode für das View-Objekt verwenden. In diesem Fall ruft das System zuerst den Listener auf. Das System ruft die Callback-Methode nur dann auf, wenn der Listener false zurückgibt.

Die Kombination der Methode onDragEvent() und View.OnDragListener entspricht der Kombination aus onTouchEvent() und View.OnTouchListener, die mit Touch-Ereignissen verwendet werden.