Wichtige Konzepte

Compose ausprobieren
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Informationen zum Drag-and-drop-Verfahren in Compose

In den folgenden Abschnitten werden einige wichtige Konzepte für das Drag-and-drop-Verfahren erläutert.

Drag-and-drop-Prozess

Beim Drag-and-drop-Verfahren gibt es vier Schritte oder Status: „Started“ (Gestartet), „Continuing“ (Fortgesetzt), „Dropped“ (Abgelegt) und „Ended“ (Beendet).

Gestartet

Als Reaktion auf die Ziegesten eines Nutzers ruft Ihre Anwendung startDragAndDrop() auf, um das System zum Starten eines Drag-and-drop-Vorgangs aufzufordern. Die Argumente der Methode bieten folgende Möglichkeiten:

  • Die Daten, die Sie verschieben möchten.
  • Ein Callback zum Zeichnen des Schattens beim Ziehen
  • Metadaten, die die gezogenen Daten beschreiben
  • Das System ruft daraufhin Ihre Anwendung zurück, um einen Schatten für das Ziehen abzurufen. Das System zeigt dann den Schatten des Ziehens auf dem Gerät an.
  • Als Nächstes sendet das System ein Drag-Ereignis mit dem Aktionstyp ACTION_DRAG_STARTED an den Drag-Ereignis-Listener aller View-Objekte im aktuellen Layout. Damit weiterhin Drag-Ereignisse empfangen werden, einschließlich eines möglichen Drop-Ereignisses, muss der Drag-Ereignis-Listener true zurückgeben. Dadurch wird der Listener beim System registriert. Nur registrierte Listener erhalten weiterhin Drag-Ereignisse. An dieser Stelle können Listener auch das Erscheinungsbild ihres Drop-Zielobjekts View ändern, um anzuzeigen, dass die Ansicht ein Drop-Ereignis akzeptieren kann.
  • Wenn der Drag-Ereignis-Listener false zurückgibt, werden erst dann Drag-Ereignisse für den aktuellen Vorgang empfangen, wenn das System ein Drag-Ereignis mit dem Aktionstyp ACTION_DRAG_ENDED sendet. Durch das Zurückgeben von false teilt der Listener dem System mit, dass er nicht am Drag-and-drop-Vorgang interessiert ist und die gezogenen Daten nicht akzeptieren möchte.
Wird fortgesetzt
Der Nutzer zieht das Element weiter. Wenn der Schatten des Objekts, das verschoben wird, den Begrenzungsrahmen eines Drop-Ziels schneidet, sendet das System ein oder mehrere Drag-Ereignisse an den Drag-Ereignis-Listener des Ziels. Der Listener kann das Aussehen des Drop-Ziels View als Reaktion auf das Ereignis ändern. Wenn das Ereignis beispielsweise angibt, dass der Schatten des Objekts, das gezogen wird, den Begrenzungsrahmen des Drop-Ziels betritt (Aktiontyp ACTION_DRAG_ENTERED), kann der Listener reagieren, indem er das View hervorhebt.
Abgebrochen
Der Nutzer lässt den Schatten des Ziehvorgangs innerhalb des Begrenzungsrahmens eines Drop-Ziels los. Das System sendet dem Listener des Drop-Ziels ein Ziehereignis mit dem Aktionstyp ACTION_DROP. Das Drag-Ereignisobjekt enthält die Daten, die über den Aufruf von startDragAndDrop() an das System übergeben werden, wodurch der Vorgang gestartet wird. Der Listener muss dem System den booleschen Wert true zurückgeben, wenn er die verworfenen Daten erfolgreich verarbeitet hat. : Dieser Schritt tritt nur auf, wenn der Nutzer den Schatten des Objekts innerhalb des Begrenzungs-Quaders eines View ablegt, dessen Listener für das Empfangen von Drag-Ereignissen registriert ist (Drop-Ziel). Wenn der Nutzer den Schatten in einer anderen Situation loslässt, wird kein ACTION_DROP-Drag-Ereignis gesendet.
Beendet

Nachdem der Nutzer den Schatten losgelassen und das System

ein Drag-Ereignis mit dem Aktionstyp ACTION_DROP auslöst, sendet das System bei Bedarf ein Drag-Ereignis mit dem Aktionstyp ACTION_DRAG_ENDED, um anzuzeigen, dass der Drag-and-drop-Vorgang beendet ist. Das geschieht unabhängig davon, wo der Nutzer den Schatten loslässt. Das Ereignis wird an alle Listener gesendet, die zum Empfang von Drag-Ereignissen registriert sind, auch wenn der Listener auch das Ereignis ACTION_DROP empfängt.

Die einzelnen Schritte werden im Abschnitt Drag-and-drop-Vorgang ausführlicher beschrieben.

Drag-Events

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

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

Tabelle 1 Aktionstypen für DragEvent

Aktionstyp Bedeutung
ACTION_DRAG_STARTED Die Anwendung ruft startDragAndDrop() auf und erhält einen Schatten, der beim Ziehen zu sehen ist. Wenn der Listener weiterhin Drag-Ereignisse für diese Aktion erhalten möchte, muss er dem System den booleschen Wert true zurückgeben.
ACTION_DRAG_ENTERED Der Schatten des Ziehens betritt den Begrenzungsrahmen des View des Drag-Event-Listeners. Dies ist der erste Ereignisaktionstyp, den der Listener empfängt, wenn der Schatten des Ziehvorgangs den Begrenzungsrahmen betritt.
ACTION_DRAG_LOCATION Nach einem ACTION_DRAG_ENTERED-Ereignis befindet sich der Schatten des Ziehens noch innerhalb des Begrenzungsrahmens der View des Drag-Ereignis-Listeners.
ACTION_DRAG_EXITED Nach einem ACTION_DRAG_ENTERED- und mindestens einem ACTION_DRAG_LOCATION-Ereignis bewegt sich der Schatten des Drag-Events außerhalb des Begrenzungs-Quadranten der View des Drag-Event-Listeners.
ACTION_DROP Der Schatten wird über der View des Drag-Event-Listeners freigegeben. Dieser Aktionstyp wird nur an den Listener eines View-Objekts gesendet, wenn der Listener als Reaktion auf das ACTION_DRAG_STARTED-Drag-Ereignis den booleschen Wert true zurückgibt. Dieser Aktionstyp wird nicht gesendet, wenn der Nutzer den Schatten des Ziehvorgangs über einem View loslässt, dessen Listener nicht registriert ist, oder wenn der Nutzer den Schatten des Ziehvorgangs über etwas loslässt, das nicht zum aktuellen Layout gehört.

Der Listener gibt den booleschen Wert true zurück, wenn die Auslieferung erfolgreich verarbeitet wurde. 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 die Auslieferung erfolgreich war. Der Listener muss getResult() aufrufen, wie in Tabelle 2 dargestellt, um den Wert abzurufen, der als Antwort auf ACTION_DROP zurückgegeben wird. Wenn kein ACTION_DROP-Ereignis gesendet wird, gibt getResult() false zurück.

Das DragEvent-Objekt enthält auch die Daten und Metadaten, die Ihre Anwendung dem System beim Aufruf von startDragAndDrop() zur Verfügung stellt. 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 keine gültigen Daten für einen bestimmten Aktionstyp enthält, wird je nach Ergebnistyp null oder 0 zurückgegeben.

Drag-Schatten

Während eines Drag-and-drop-Vorgangs zeigt das System ein Bild an, das der Nutzer zieht. Beim Verschieben von Daten steht dieses Bild für die Daten, die gezogen werden. Bei anderen Vorgängen stellt das Bild einen Aspekt des Ziehens dar.

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

Die Klasse View.DragShadowBuilder hat zwei Konstruktoren:

View.DragShadowBuilder(View)

Dieser Konstruktor akzeptiert alle View-Objekte Ihrer Anwendung. Der Konstruktor speichert das View-Objekt im View.DragShadowBuilder-Objekt, damit die Callbacks darauf zugreifen können, um den Schatten zu erstellen. Die Ansicht muss keine View sein, die der Nutzer auswählt, um den Ziehvorgang zu starten.

Wenn Sie diesen Konstruktor verwenden, müssen Sie View.DragShadowBuilder nicht erweitern oder seine Methoden überschreiben. Standardmäßig wird ein Schatten angezeigt, der der View entspricht, die Sie als Argument übergeben. Er ist zentriert unter der Stelle, an der der Nutzer den Bildschirm berührt.

View.DragShadowBuilder()

Wenn Sie diesen Konstruktor verwenden, ist im View.DragShadowBuilder-Objekt kein View-Objekt verfügbar. Das Feld ist auf null gesetzt. Sie müssen View.DragShadowBuilder erweitern und seine Methoden überschreiben, da sonst ein unsichtbarer Schatten entsteht. Das System gibt keinen Fehler aus.

Die Klasse View.DragShadowBuilder hat zwei Methoden, die zusammen den Schatten beim Ziehen erzeugen:

onProvideShadowMetrics()

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

outShadowSize:ein Point-Objekt. Die Breite des Schattens wird in x und die Höhe in y angegeben.

outShadowTouchPoint:ein Point-Objekt. Der Touchpoint ist die Stelle innerhalb des Schattens, die während des Ziehens unter dem Finger des Nutzers sein muss. Die X-Position wird in x und die Y-Position in y eingegeben.

onDrawShadow()

Unmittelbar nach dem Aufruf von onProvideShadowMetrics() ruft das System onDrawShadow() auf, um den Schatten zu erstellen. Die Methode hat ein einziges Argument, ein Canvas-Objekt, das das System aus den Parametern erstellt, die Sie in onProvideShadowMetrics() angeben. Die Methode zeichnet den Schatten des Objekts auf dem angegebenen Canvas.

Halten Sie die Größe des Schattens beim Ziehen klein, um die Leistung zu verbessern. Für einen einzelnen Artikel können Sie ein Symbol verwenden. Bei einer Auswahl mehrerer Elemente sollten Sie Symbole in einem Stapel verwenden, anstatt vollständige Bilder auf dem Bildschirm zu verteilen.

Event-Listener und Callback-Methoden ziehen

Ein View empfängt Drag-Events mit einem Drag-Ereignis-Listener, der View.OnDragListener implementiert, oder mit der onDragEvent()-Callback-Methode der Ansicht. Wenn das System die Methode oder den Listener aufruft, wird ein DragEvent-Argument übergeben.

In den meisten Fällen ist die Verwendung eines Listeners vorzuziehen. Beim Entwerfen von UIs werden View-Klassen in der Regel nicht als Unterklasse erstellt. Wenn Sie jedoch die Rückrufmethode 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. Sie können sie auch als anonyme Inline-Klasse oder 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 für eine Ansicht einen OnReceiveContentListener fest. Weitere Informationen finden Sie unter setOnReceiveContentListener(). Die Methode onDragEvent() führt dann standardmäßig Folgendes aus:

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

  • Gibt „wahr“ zurück, wenn die per Drag-and-drop eingefügten Daten in die Ansicht abgelegt werden und OnReceiveContentListener einen Teil des Inhalts beansprucht.

Definieren Sie die OnReceiveContentListener, um die Daten speziell für Ihre App zu verarbeiten. Verwenden Sie für die Abwärtskompatibilität bis API-Level 24 die Jetpack-Version von OnReceiveContentListener.

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

Die Kombination der Methode onDragEvent() und View.OnDragListener ist analog zur Kombination von onTouchEvent() und View.OnTouchListener, die bei Touch-Ereignissen verwendet wird.