Kluczowe pojęcia

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ów View 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 obiektu View, 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łania ACTION_DRAG_ENDED. Zwracając false, 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łania ACTION_DRAG_ENTERED), odbiornik może zareagować, podświetlając View.
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 funkcji startDragAndDrop(), 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 element View, którego odbiornik jest zarejestrowany do odbierania zdarzeń przeciągania (elementu docelowego). Jeśli użytkownik zwolni cień w innej sytuacji, zdarzenie przeciągnięcia ACTION_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łania ACTION_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 zdarzenie ACTION_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:

Tabela 1. Typy działań DragEvent

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ą true. W przeciwnym razie musi zwrócić wartość false.

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.

Tabela 2. Prawidłowe dane DragEvent według typu działania

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 obiekt View w obiekcie View.DragShadowBuilder, więc wywołania zwrotne mogą uzyskać do niego dostęp w celu utworzenia cienia. Widok nie musi być widokiem View, 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 obiekt View 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 obiekt View. Pole jest ustawione na null. Musisz rozszerzyć zakres View.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: obiekt Point. Szerokość cienia przeciągania zostanie wpisana w polu x, a jego wysokość – w y.

outShadowTouchPoint: obiekt Point. 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 pozycji x, a pozycja Y – w y.

onDrawShadow()

Bezpośrednio po wywołaniu onProvideShadowMetrics() system wywołuje metodę onDrawShadow(), aby utworzyć cień przeciągania. Ma ona jeden argument – obiekt Canvas, który system tworzy na podstawie parametrów podanych w parametrze onProvideShadowMetrics(). Ta metoda generuje cień przeciągania na podany element Canvas.

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 obiekt ContentInfo. 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.