W kolejnych sekcjach opisano kilka kluczowych pojęć związanych z przeciąganiem i upuszczaniem.
Proces przeciągania i upuszczania
Przeciąganie i upuszczanie ma cztery etapy: „rozpoczęte”, „kontynuowanie”, „upuszczenie” i „zakończenie”.
- Rozpoczęto
W odpowiedzi na gest przeciągania przez użytkownika aplikacja wywołuje funkcję
startDragAndDrop()
, aby nakazać systemowi rozpoczęcie operacji przeciągania i upuszczania. Argumenty metody zapewniają:- Dane do przeciągnięcia.
- Wywołanie zwrotne dotyczące rysowania cienia
- Metadane opisujące przeciągnięte dane
- W odpowiedzi system wywołuje aplikację, aby uzyskać cień. Następnie system wyświetli na urządzeniu cień.
- Następnie system wysyła zdarzenie przeciągania z typem działania
ACTION_DRAG_STARTED
do odbiornika wszystkich obiektówView
w bieżącym układzie. Aby nadal otrzymywać zdarzenia przeciągania, w tym możliwe zdarzenia upuszczania, detektor musi zwrócić wartośćtrue
. To spowoduje zarejestrowanie słuchacza w systemie. Tylko zarejestrowane detektory otrzymują zdarzenia przeciągania. Na tym etapie detektory mogą też zmieniać wygląd obiektuView
, aby wskazać, że widok może zaakceptować zdarzenie spadku. - Jeśli detektor zdarzeń przeciągania zwróci wartość
false
, nie otrzyma zdarzeń przeciągania w ramach bieżącej operacji, dopóki system nie wyśle zdarzenia przeciągania z typem działaniaACTION_DRAG_ENDED
. Zwracającfalse
, odbiornik informuje system, że nie jest zainteresowany operacją przeciągania i upuszczania oraz że nie chce akceptować przeciągniętych danych.
- Kontynuuję
- Użytkownik kontynuuje przeciąganie. Gdy cień przeciągania przecina ramkę ograniczającą elementu docelowego, system wysyła co najmniej 1 zdarzenie przeciągania do detektora zdarzeń przeciągania w miejscu docelowym. W odpowiedzi na zdarzenie detektor może zmienić wygląd miejsca docelowego
View
. Jeśli na przykład zdarzenie wskazuje, że cień przeciągania wchodzi do ramki ograniczającej celu (typ działaniaACTION_DRAG_ENTERED
), odbiornik może zareagować, podświetlającView
. - Usunięto
- Użytkownik puści cień w obrębie ramki ograniczającej cel. System wysyła do detektora elementu docelowego zdarzenie przeciągania z typem działania
ACTION_DROP
. Obiekt zdarzenia przeciągania zawiera dane, które są przekazywane do systemu w wywołaniu funkcjistartDragAndDrop()
, które uruchamiają operację. Jeśli detektor przetworzy upuszczone dane, powinien zwrócić do systemu wartość logicznątrue
. Ten krok występuje tylko wtedy, gdy użytkownik upuść cień w ramce ograniczającej elementView
, którego odbiornik jest zarejestrowany do odbierania zdarzeń przeciągania (elementu docelowego). Jeśli użytkownik zwolni cień w innej sytuacji, zdarzenie przeciągnięciaACTION_DROP
nie zostanie wysłane. - Zakończone
Po zwolnieniu cienia przez użytkownika i wysłaniu przez system
zdarzenia przeciągania z typem działania
ACTION_DROP
. W razie potrzeby system wyśle zdarzenie przeciągania z typem 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 zwolni cień. Zdarzenie jest wysyłane do każdego detektora, który został zarejestrowany do odbierania zdarzeń przeciągania nawet wtedy, gdy detektor też otrzyma zdarzenieACTION_DROP
.
Każdy z nich został szczegółowo opisany w sekcji Przeciąganie i upuszczanie.
Przeciąganie zdarzeń
System wysyła zdarzenie przeciągania w formie obiektu DragEvent
, który zawiera typ działania opisującego to, co się dzieje w procesie przeciągania i upuszczania. W zależności od typu działania obiekt może też zawierać inne dane.
Detektory zdarzeń przeciągania otrzymują obiekt DragEvent
. Aby poznać rodzaj działania, słuchacze wywołują metodę DragEvent.getAction()
.
Stałe w klasie DragEvent
może mieć 6 możliwych wartości zdefiniowanych przez stałe w tabeli 1:
Typ działania | Znaczenie |
---|---|
ACTION_DRAG_STARTED |
Aplikacja wywołuje funkcję startDragAndDrop() i uzyskuje cień przeciągania. Jeśli detektor chce nadal otrzymywać zdarzenia przeciągania w ramach tej operacji, musi zwrócić do systemu wartość logiczną true .
|
ACTION_DRAG_ENTERED |
Cień przeciągania wchodzi w granicę detektora zdarzeń przeciągania: View . Jest to pierwszy typ działania zdarzenia odbieranego przez odbiornik, gdy cień przeciągania wejdzie w ramkę ograniczającą.
|
ACTION_DRAG_LOCATION |
Po wystąpieniu zdarzenia ACTION_DRAG_ENTERED cień przeciągania wciąż mieści się w ramce ograniczającej zdarzenie View odbiornika.
|
ACTION_DRAG_EXITED |
Po wystąpieniu ACTION_DRAG_ENTERED i co najmniej 1 zdarzeniu ACTION_DRAG_LOCATION cień przeciągania przesuwa się poza ramkę ograniczającą odbiornik View zdarzenia przeciągania.
|
ACTION_DROP |
Cień przeciągania zwolni się nad obiektem View detektora zdarzeń przeciągania. Ten typ działania jest wysyłany do detektora obiektu View tylko wtedy, gdy w odpowiedzi na zdarzenie przeciągania ACTION_DRAG_STARTED zwraca on wartość logiczną true . Ten typ działania nie jest wysyłany, jeśli użytkownik zwolni cień przez przeciąganie na element View , którego detektor nie jest zarejestrowany, lub jeśli użytkownik zwolni cień przeciągania na element, który nie jest częścią bieżącego układu.
Jeśli udało się przetworzyć spadek, odbiornik 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 wyśle żądanie ACTION_DROP , odbiór działania ACTION_DRAG_ENDED nie oznacza, że spadek się powiodła. Aby uzyskać wartość zwracaną w odpowiedzi na ACTION_DROP , detektor musi wywołać getResult() , jak pokazano w tabeli 2. Jeśli zdarzenie ACTION_DROP nie zostało wysłane, getResult() zwraca false .
|
Obiekt DragEvent
zawiera też dane i metadane, które aplikacja udostępnia systemowi w wywołaniu startDragAndDrop()
. Część danych jest ważna 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 Przeciąganie i upuszczanie.
Wartość: getAction() |
Wartość: getClipDescription() |
Wartość: getLocalState() |
Wartość: getX() |
Wartość: getY() |
Wartość: getClipData() |
Wartość: getResult() |
---|---|---|---|---|---|---|
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, który został przeciągnięty przez użytkownika. Na potrzeby przenoszenia danych ten obraz przedstawia przeciągane dane. W przypadku innych operacji obraz przedstawia pewien aspekt przeciągania.
Jest to tzw. cień przez przeciąganie. Tworzysz ją za pomocą metod zadeklarowanych dla obiektu View.DragShadowBuilder
. Po rozpoczęciu operacji przeciągania i upuszczania za pomocą startDragAndDrop()
przekazujesz konstruktora 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 wszystkie obiekty
View
aplikacji. Konstruktor przechowuje obiektView
w obiekcieView.DragShadowBuilder
, więc wywołania zwrotne mogą uzyskać do niego dostęp w celu utworzenia cienia. Widok nie musi być widokiemView
, który użytkownik wybierze, aby rozpocząć operację przeciągania.Jeśli używasz tego konstruktora, nie musisz rozszerzać obiektu
View.DragShadowBuilder
ani zastępować jego metod. Domyślnie otrzymujesz cień przeciągania, który wygląda tak samo jak obiektView
przekazywany jako argument, położony pod lokalizacją, w której użytkownik dotyka ekranu.View.DragShadowBuilder()
Jeśli używasz tego konstruktora, w obiekcie
View.DragShadowBuilder
nie będzie dostępny żaden obiektView
. Pole jest ustawione nanull
. Musisz rozszerzyć zakresView.DragShadowBuilder
i zastąpić stosowane w nim metody. W przeciwnym razie otrzymasz niewidoczny cień. System nie zgłasza 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 funkcji
startDragAndDrop()
. Użyj tej metody, aby przesłać do systemu wymiary i punkt styku przeciągania cienia. Ta metoda ma 2 parametry:outShadowSize
: obiektPoint
. Szerokość cienia przeciągania zostanie wpisana w polux
, a jego wysokość – wy
.outShadowTouchPoint
: obiektPoint
. Punkt styczności z klientem to miejsce w cieniu, które musi znajdować się pod palcem użytkownika podczas przeciągania. Pozycja X pojawia się w pozycjix
, a pozycja Y – wy
.onDrawShadow()
Bezpośrednio po wywołaniu
onProvideShadowMetrics()
system wywołuje metodęonDrawShadow()
, aby utworzyć cień przeciągania. Ma ona jeden argument – obiektCanvas
, który system tworzy na podstawie parametrów podanych w parametrzeonProvideShadowMetrics()
. Ta metoda generuje cień przeciągania na podany elementCanvas
.
Aby poprawić wydajność, rozmiar cienia przeciągania powinien być mały. W przypadku pojedynczego produktu możesz użyć ikony. Jeśli wybierasz wiele produktów, lepiej jest umieszczać ikony w stosunku do siebie, a nie całe obrazy rozłożone na ekranie.
Przeciąganie detektorów zdarzeń i metod wywołań zwrotnych
Element View
otrzymuje zdarzenia przeciągania z detektorem zdarzeń przeciągania, który implementuje metodę View.OnDragListener
, lub za pomocą metody wywołania zwrotnego onDragEvent()
widoku. Gdy system wywoła metodę lub detektor, zwróci argument DragEvent
.
W większości przypadków lepiej użyć odbiornika niż wywołania zwrotnego. Podczas projektowania interfejsów zwykle nie umieszczasz w klasie klas View
, ale korzystanie z metody wywołania zwrotnego wymusza utworzenie podklas w celu zastąpienia tej metody. W ramach porównania możesz wdrożyć 1 klasę detektora, a następnie używać jej z wieloma różnymi obiektami View
. Możesz ją też zaimplementować jako anonimową klasę wbudowaną lub wyrażenie lambda. Aby ustawić odbiornik obiektu View
, wywołaj setOnDragListener()
.
Zamiast tego możesz zmienić domyślną implementację parametru onDragEvent()
bez zastępowania tej metody. Ustaw OnReceiveContentListener
w widoku danych. Więcej informacji znajdziesz w sekcji setOnReceiveContentListener()
.
Następnie metoda onDragEvent()
domyślnie wykonuje te działania:
- Zwraca wartość „true” (prawda) w odpowiedzi na wywołanie funkcji
startDragAndDrop()
. Wywołuje metodę
performReceiveContent()
, jeśli dane przeciągnij i upuść w widoku. Dane są przekazywane do metody jako obiektContentInfo
. Metoda wywołuje metodęOnReceiveContentListener
.Zwraca wartość „prawda”, jeśli dane przeciągnij i upuść w widoku, a
OnReceiveContentListener
zużywa dowolną treść.
Określ OnReceiveContentListener
do obsługi danych specjalnie na potrzeby Twojej aplikacji. Aby zapewnić zgodność wsteczną do poziomu interfejsu API 24, użyj wersji Jetpack OnReceiveContentListener
.
Możesz mieć detektor zdarzeń przeciągania i metodę wywołania zwrotnego dla obiektu View
. W takim przypadku system najpierw wywoła odbiornik. System nie wywołuje metody wywołania zwrotnego, chyba że odbiornik zwróci wartość false
.
Kombinacja metody onDragEvent()
i View.OnDragListener
jest podobna do kombinacji elementów onTouchEvent()
i View.OnTouchListener
używanych ze zdarzeniami dotknięcia.