W poniższych sekcjach znajdziesz kilka kluczowych pojęć dotyczących procesu przeciągania i upuszczania.
Proces przeciągania i upuszczania
Proces przeciągania i upuszczania obejmuje 4 etapy lub stany: rozpoczęcie, kontynuowanie, upuszczenie i zakończenie.
- Rozpoczęto
W odpowiedzi na gest przeciągania użytkownika aplikacja wywołuje funkcję
startDragAndDrop()
, aby zlecić systemowi rozpoczęcie operacji przeciągania i upuszczania. Argumenty metody:- Dane, które mają być przeciągane.
- Callback do rysowania cienia przeciągania.
- metadane opisujące przeciągnięte dane;
- System odpowiada, wywołując Twoją aplikację, aby uzyskać informacje o przeciągniętym obiekcie. System wyświetli na urządzeniu cień przeciągania.
- Następnie system wysyła zdarzenie przeciągania z typem działania
ACTION_DRAG_STARTED
do listenera zdarzenia przeciągania wszystkich obiektówView
w bieżącym układzie. Aby nadal otrzymywać zdarzenia przeciągania (w tym zdarzenie upuszczenia), detektor zdarzeń przeciągania musi zwracać wartośćtrue
. Spowoduje to zarejestrowanie detektora w systemie. Tylko zarejestrowani słuchacze będą nadal otrzymywać zdarzenia przeciągania. W tym momencie detektory mogą też zmienić wygląd obiektu celuView
, aby pokazać, że widok może obsłużyć zdarzenie drop. - Jeśli detektor zdarzenia przeciągania zwraca wartość
false
, nie otrzymuje zdarzeń przeciągania dotyczących bieżącej operacji, dopóki system nie wyśle zdarzenia przeciągania z typem działaniaACTION_DRAG_ENDED
. Zwracającfalse
, listener informuje system, że nie jest zainteresowany operacją przeciągania i nie chce akceptować przeciąganych danych.
- Kontynuuję
- Użytkownik kontynuuje przeciąganie. Gdy cień przeciągania przecina ogranicznik celu przeciągania, system wysyła co najmniej 1 zdarzenie przeciągania do detektora zdarzenia przeciągania celu. W odpowiedzi na to zdarzenie detektor może zmienić wygląd celu
View
. Jeśli na przykład zdarzenie wskazuje, że cień przeciągania wchodzi w ramy obszaru docelowego – typ działaniaACTION_DRAG_ENTERED
– odbiorca może zareagować, podświetlając elementView
. - Usunięto
- Użytkownik puszcza cień przeciągania w ramce obszaru docelowego. System wysyła do detektora celu upuszczenia zdarzenie przeciągania z typem działania
ACTION_DROP
. Obiekt zdarzenia przeciągania zawiera dane przekazywane do systemu w wywołaniu funkcjistartDragAndDrop()
, która inicjuje operację. Wyświetlacz powinien zwrócić do systemu wartość logicznątrue
, jeśli przetworzy dane. : Ten krok występuje tylko wtedy, gdy użytkownik upuści cień przeciągania w ramceView
, którego odbiornik jest zarejestrowany do odbierania zdarzeń przeciągania (cel upuszczenia). Jeśli użytkownik zwolnił cień przeciągania w dowolnej innej sytuacji, nie zostanie wysłane żadne zdarzenieACTION_DROP
przeciągania. - Zakończona
Gdy użytkownik puści cień przeciągania, a system wyśle
Jeśli to konieczne, system wysyła zdarzenie przeciągania o typie działania
ACTION_DROP
, a potem zdarzenie przeciągania o typie działaniaACTION_DRAG_ENDED
, aby wskazać, że operacja przeciągania i upuszczania została zakończona. Dzieje się tak niezależnie od tego, gdzie użytkownik puści cień. Zdarzenie jest wysyłane do każdego detektora zarejestrowanego do odbierania zdarzeń przeciągania, nawet jeśli detektor otrzymuje też zdarzenieACTION_DROP
.
Każdy z tych kroków jest opisany bardziej szczegółowo w sekcji Operacja przeciągania i upuszczania.
Zdarzenia przeciągania
System wysyła zdarzenie przeciągania w postaci obiektu DragEvent
, który zawiera typ działania opisujący, co dzieje się podczas procesu przeciągania i upuszczania. W zależności od typu działania obiekt może też zawierać inne dane.
Detektory zdarzeń przeciągnięcia otrzymują obiekt DragEvent
. Aby uzyskać typ działania, słuchacze wywołują funkcję DragEvent.getAction()
.
W klasie DragEvent
zdefiniowano 6 możliwych wartości stałych, które są opisane w tabeli 1:
Tabela 1. Typy zdarzeń DragEvent
Typ działania | Znaczenie |
---|---|
ACTION_DRAG_STARTED |
Aplikacja wywołuje startDragAndDrop() i uzyskiwanie cienia przeciągania. Jeśli odbiorca chce nadal otrzymywać zdarzenia przeciągania w ramach tej operacji, musi zwrócić wartość logiczną true do systemu.
|
ACTION_DRAG_ENTERED |
Cień przeciągania wchodzi w ramy kontenera detektora zdarzeń przeciągania (View ). Jest to pierwszy typ działania zdarzenia, które detektor otrzymuje, gdy cień przeciągania wejdzie w obszar ograniczający.
|
ACTION_DRAG_LOCATION |
Po zdarzeniu ACTION_DRAG_ENTERED cień przeciągania nadal znajduje się w ramach prostokąta ograniczającego detektora zdarzenia przeciągania View .
|
ACTION_DRAG_EXITED |
Po zdarzeniu ACTION_DRAG_ENTERED i co najmniej jednym zdarzeniu ACTION_DRAG_LOCATION cień przeciągania przesuwa się poza prostokąt ograniczający detektora zdarzenia przeciągania View .
|
ACTION_DROP |
Cień przeciągania zostaje zwolniony nad detektorem zdarzenia przeciągania
View . Ten typ działania jest wysyłany do detektora zdarzenia View obiektu tylko wtedy, gdy detektor zwraca wartość logiczną true w odpowiedzi na zdarzenie przeciągania ACTION_DRAG_STARTED . Ten typ działania nie jest wysyłany, jeśli użytkownik puści cień przeciągania nad View , którego słuchacz nie jest zarejestrowany, lub jeśli użytkownik puści cień przeciągania nad elementem, który nie jest częścią bieżącego układu.
Listener zwraca wartość logiczną |
ACTION_DRAG_ENDED |
System kończy operację przeciągania i upuszczania. Ten typ działania nie musi być poprzedzony zdarzeniem ACTION_DROP . Jeśli system wysyła zdarzenie ACTION_DROP , otrzymanie typu działania ACTION_DRAG_ENDED nie oznacza, że drop się powiódł. Aby uzyskać wartość zwracaną w odpowiedzi na wywołanie ACTION_DROP , detektor musi wywołać funkcję getResult() , jak pokazano w tabeli 2. Jeśli zdarzenie ACTION_DROP nie zostało wysłane, funkcja getResult() zwraca wartość false .
|
Obiekt DragEvent
zawiera też dane i metadane, które aplikacja przekazuje do systemu w wywołaniu funkcji startDragAndDrop()
. Niektóre dane są ważne tylko w przypadku określonych typów działań, jak podano w tabeli 2. Więcej informacji o zdarzeniach i powiązanych z nimi danych znajdziesz w sekcji Operacja przeciągania i upuszczania.
Tabela 2. Dane zdarzenia Valid DragEvent według typu działania
getAction() wartość |
getClipDescription() wartość |
getLocalState() wartość |
getX() wartość |
getY() wartość |
getClipData() wartość |
getResult() wartość |
---|---|---|---|---|---|---|
ACTION_DRAG_STARTED |
✓ | ✓ | ||||
ACTION_DRAG_ENTERED |
✓ | ✓ | ||||
ACTION_DRAG_LOCATION |
✓ | ✓ | ✓ | ✓ | ||
ACTION_DRAG_EXITED |
✓ | ✓ | ||||
ACTION_DROP |
✓ | ✓ | ✓ | ✓ | ✓ | |
ACTION_DRAG_ENDED |
✓ | ✓ |
Metody DragEvent
getAction()
, describeContents()
, writeToParcel()
i toString()
zawsze zwracają prawidłowe dane.
Jeśli metoda nie zawiera prawidłowych danych dla określonego typu działania, zwraca null
lub 0, w zależności od typu wyniku.
Przeciąganie cienia
Podczas przeciągania i upuszczania system wyświetla obraz przeciągany przez użytkownika. W przypadku przenoszenia danych obraz ten przedstawia przeciągane dane. W przypadku innych operacji obraz przedstawia pewien aspekt operacji przeciągania.
Obraz nazywa się przeciąganym cieniem. Tworzysz go za pomocą metod zadeklarowanych dla obiektu View.DragShadowBuilder
. Gdy rozpoczynasz operację przeciągania i upuszczania za pomocą startDragAndDrop()
, przekazujesz kreator do systemu. W ramach odpowiedzi na startDragAndDrop()
system wywołuje metody wywołania zwrotnego zdefiniowane w View.DragShadowBuilder
, aby uzyskać cień przeciągania.
Klasa View.DragShadowBuilder
ma 2 konstruktory:
View.DragShadowBuilder(View)
Ten konstruktor akceptuje dowolne obiekty
View
aplikacji. Konstruktor przechowuje obiektView
w obiekcieView.DragShadowBuilder
, aby funkcje zwracane mogły z niego korzystać podczas tworzenia cienia przeciągania. Widok nie musi być widokiemView
, który użytkownik wybiera, aby rozpocząć przeciąganie.Jeśli używasz tej metody konstruktora, nie musisz rozszerzać klasy
View.DragShadowBuilder
ani zastępować jej metod. Domyślnie otrzymujesz cień przeciągania o takim samym wyglądzie jakView
przekazany jako argument, który jest wyśrodkowany pod miejscem, w którym użytkownik dotyka ekranu.View.DragShadowBuilder()
Jeśli użyjesz tej metody konstruktora, w obiekcie
View.DragShadowBuilder
nie będzie dostępnego obiektuView
. To pole ma wartośćnull
. Musisz rozszerzyć klasęView.DragShadowBuilder
i zastąpić jej metody, w przeciwnym razie będziesz mieć niewidoczną cieniowaną ramkę. System nie zwraca błędu.
Klasa View.DragShadowBuilder
ma 2 metody, które razem tworzą cień przeciągania:
onProvideShadowMetrics()
System wywołuje tę metodę natychmiast po wywołaniu
startDragAndDrop()
. Użyj tej metody, aby wysłać wymiary i punkt dotykowy cienia przeciągania do systemu. Metoda ma 2 parametry:outShadowSize
: obiektPoint
. Szerokość cienia przeciągania jest podawana wx
, a wysokość – wy
.outShadowTouchPoint
: obiektPoint
. Punkt styczności to lokalizacja w cieniu przeciągania, która musi znajdować się pod palcem użytkownika podczas przeciągania. Jego pozycja X znajduje się w miejscux
, a pozycja Y – w miejscuy
.onDrawShadow()
Natychmiast po wywołaniu funkcji
onProvideShadowMetrics()
system wywołuje funkcjęonDrawShadow()
, aby utworzyć cień przeciągania. Metoda ma 1 argument, obiektCanvas
, który system tworzy na podstawie parametrów podanych wonProvideShadowMetrics()
. Metoda rysuje cień przeciągania na podanym obiekcieCanvas
.
Aby zwiększyć wydajność, zmniejsz rozmiar cienia przeciągania. W przypadku pojedynczego elementu możesz użyć ikony. W przypadku wielu elementów możesz użyć ikon w grupie, a nie pełnych obrazów rozłożonych na ekranie.
Przeciąganie detektorów zdarzeń i metod wywołania
Obiekt View
odbiera zdarzenia przeciągania za pomocą detektora zdarzeń przeciągania, który implementuje funkcję View.OnDragListener
, lub za pomocą metody wywołania onDragEvent()
widoku. Gdy system wywołuje metodę lub interfejs Listener, przekazuje argument DragEvent
.
W większości przypadków lepszym rozwiązaniem jest użycie listenera niż metody callback. Podczas projektowania interfejsu użytkownika zwykle nie tworzysz podklas klas View
, ale korzystanie z metody wywołania zwrotnego wymusza tworzenie podklas, aby zastąpić metodę. W porównaniu z tym możesz zaimplementować jedną klasę listenera, a potem używać jej z wielu różnych obiektów View
. Możesz też zaimplementować go jako anonimową klasę wbudowaną lub wyrażenie lambda. Aby ustawić detektor dla obiektu View
, wywołaj funkcję setOnDragListener()
.
Możesz też zmodyfikować domyślną implementację funkcji onDragEvent()
bez zastępowania metody. Ustaw OnReceiveContentListener
w widoku. Więcej informacji znajdziesz w sekcji setOnReceiveContentListener()
.
Metoda onDragEvent()
wykonuje wtedy domyślnie te czynności:
- Zwraca wartość „PRAWDA” w odpowiedzi na wywołanie funkcji
startDragAndDrop()
. Połączeń
performReceiveContent()
jeśli dane przeciągane i upuszczane są w widoku. Dane są przekazywane metodzie jako obiektContentInfo
. Metoda wywołuje funkcjęOnReceiveContentListener
.Zwraca wartość „prawda”, jeśli dane przeciągane i upuszczane są umieszczane w widoku, a element
OnReceiveContentListener
zużywa jakąś zawartość.
Zdefiniuj OnReceiveContentListener
, aby przetwarzać dane tylko w przypadku Twojej aplikacji. Aby zapewnić zgodność wsteczną z poziomem interfejsu API 24, użyj wersji OnReceiveContentListener
z Jetpacka.
Możesz mieć detektor zdarzeń przeciągnięcia i metodę wywołania zwrotnego dla obiektu View
. W takim przypadku system najpierw wywołuje detektor. System nie wywołuje metody callback, chyba że listener zwróci false
.
Kombinacja metody onDragEvent()
i View.OnDragListener
jest analogiczna do kombinacji onTouchEvent()
i View.OnTouchListener
stosowanej w przypadku zdarzeń dotykowych.