W kolejnych sekcjach znajdziesz opis kilku kluczowych pojęć związanych z procesem przeciągania i upuszczania.
Proces przeciągania i upuszczania
Proces przeciągania i upuszczania składa się z 4 etapów lub stanów: rozpoczęto, kontynuuję, usunięto i zakończono.
- Rozpoczęto
W odpowiedzi na gest przeciągnięcia użytkownika aplikacja wywołuje
startDragAndDrop(), aby poinformować system o rozpoczęciu operacji przeciągania i upuszczania. Argumenty metody zapewniają te informacje:- dane do przeciągnięcia;
- wywołanie zwrotne do rysowania cienia przeciągania;
- metadane opisujące przeciągane dane;
- system odpowiada, wywołując aplikację, aby uzyskać cień przeciągania. Następnie system wyświetla cień przeciągania na urządzeniu.
- Następnie system wysyła zdarzenie przeciągnięcia z typem działania
ACTION_DRAG_STARTEDdo detektora zdarzeń przeciągnięcia wszystkichViewobiektów w bieżącym układzie. Aby nadal otrzymywać zdarzenia przeciągnięcia, w tym ewentualne zdarzenie upuszczenia, detektor zdarzeń przeciągnięcia musi zwrócić wartośćtrue. Rejestruje to detektor w systemie. Tylko zarejestrowane detektory nadal otrzymują zdarzenia przeciągnięcia. W tym momencie detektory mogą też zmienić wygląd obiektuViewdocelowego miejsca upuszczenia, aby pokazać, że widok może zaakceptować zdarzenie upuszczenia. - Jeśli detektor zdarzeń przeciągnięcia zwróci wartość
false, nie będzie otrzymywać zdarzeń przeciągnięcia dla bieżącej operacji, dopóki system nie wyśle zdarzenia przeciągnięcia z typem działaniaACTION_DRAG_ENDED. Zwracając wartośćfalse, detektor informuje system, że nie jest zainteresowany operacją przeciągania i upuszczania i nie chce akceptować przeciąganych danych.
- Kontynuuję
- Użytkownik kontynuuje przeciąganie. Gdy cień przeciągania przecina ramkę ograniczającą docelowego miejsca upuszczenia, system wysyła do detektora zdarzeń przeciągnięcia docelowego miejsca upuszczenia co najmniej 1 zdarzenie przeciągnięcia. Detektor może zmienić wygląd docelowego miejsca upuszczenia
Vieww odpowiedzi na zdarzenie. Jeśli np. zdarzenie wskazuje, że cień przeciągania wchodzi w ramkę ograniczającą docelowego miejsca upuszczenia (typ działaniaACTION_DRAG_ENTERED), detektor może zareagować, wyróżniającView. - Usunięto
- Użytkownik zwalnia cień przeciągania w ramce ograniczającej docelowego miejsca upuszczenia. System wysyła do detektora docelowego miejsca upuszczenia zdarzenie przeciągnięcia z action
type
ACTION_DROP. Obiekt zdarzenia przeciągnięcia zawiera dane, które są przekazywane do systemu w wywołaniustartDragAndDrop()rozpoczynającym operację. Jeśli detektor pomyślnie przetworzy upuszczone dane, powinien zwrócić do systemu wartość logicznątrue. : ten krok występuje tylko wtedy, gdy użytkownik upuści cień przeciągania w ramce ograniczającejView, którego detektor jest zarejestrowany do odbierania zdarzeń przeciągnięcia (docelowe miejsce upuszczenia). Jeśli użytkownik zwolni cień przeciągania w innej sytuacji, nie zostanie wysłane żadne zdarzenie przeciągnięciaACTION_DROP. - Zakończono
Gdy użytkownik zwolni cień przeciągania i po tym, jak system wyśle
w razie potrzeby zdarzenie przeciągnięcia z typem działania
ACTION_DROP, system wysyła zdarzenie przeciągnięcia 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ń przeciągania. Zdarzenie jest wysyłane do każdego detektora zarejestrowanego do odbierania zdarzeń przeciągnięcia, nawet jeśli detektor odbiera też zdarzenieACTION_DROP.
Każdy z tych kroków jest szczegółowo opisany w sekcji o nazwie Operacja przeciągania i upuszczania.
Zdarzenia przeciągnięcia
System wysyła zdarzenie przeciągnięcia w postaci obiektu DragEvent, który zawiera typ działania opisujący, co dzieje się w procesie 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,
detektory wywołują
DragEvent.getAction().
Istnieje 6 możliwych wartości zdefiniowanych przez stałe w klasie DragEvent, które są opisane w tabeli 1:
Tabela 1. Typy działań DragEvent
| Typ działania | Znaczenie |
|---|---|
ACTION_DRAG_STARTED |
Aplikacja wywołuje startDragAndDrop() i uzyskuje cień przeciągania. Jeśli detektor chce nadal otrzymywać zdarzenia przeciągnięcia
dla tej operacji, musi zwrócić do systemu wartość logiczną true do
systemu.
|
ACTION_DRAG_ENTERED |
Cień przeciągania wchodzi w ramkę ograniczającą detektora zdarzeń przeciągnięcia
View. Jest to pierwszy typ działania zdarzenia, który detektor otrzymuje, gdy cień przeciągania wchodzi w ramkę ograniczającą.
|
ACTION_DRAG_LOCATION |
Po zdarzeniu
ACTION_DRAG_ENTERED cień przeciągania nadal znajduje się
w ramce ograniczającej detektora zdarzeń przeciągnięcia
View.
|
ACTION_DRAG_EXITED |
Po zdarzeniu ACTION_DRAG_ENTERED i co najmniej 1 zdarzeniu
ACTION_DRAG_LOCATION cień przeciągania przesuwa się
poza ramkę ograniczającą
View detektora zdarzeń przeciągnięcia.
|
ACTION_DROP |
Cień przeciągania zostaje zwolniony nad detektorem zdarzeń przeciągnięcia
View. Ten typ działania jest wysyłany do detektora obiektu View
true tylko wtedy, gdy detektor zwróci wartość logiczną
ACTION_DRAG_STARTED w odpowiedzi na
zdarzenie przeciągnięcia. Ten typ działania nie jest
wysyłany, jeśli użytkownik zwolni cień przeciągania nad View
którego detektor nie jest zarejestrowany, lub jeśli użytkownik zwolni cień
przeciągania nad czymś, co nie jest częścią bieżącego układu.
Jeśli detektor pomyślnie przetworzy upuszczenie, 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 ACTION_DROP, otrzymanie
typu działaniaACTION_DRAG_ENDED nie oznacza, że
upuszczenie się powiodło. 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 zostanie wysłane, to
getResult() zwróci wartość false.
|
Obiekt DragEvent zawiera też dane i metadane, które aplikacja przekazuje do systemu w wywołaniu startDragAndDrop(). Niektóre dane są prawidłowe tylko w przypadku określonych typów działań, jak podsumowano w tabeli 2. Więcej
informacji o zdarzeniach i powiązanych z nimi danych znajdziesz w sekcji A
Operacja przeciągania i upuszczania.
Tabela 2. Prawidłowe dane 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 danego typu działania, zwraca wartość null lub 0, w zależności od typu wyniku.
Cień przeciągania
Podczas operacji przeciągania i upuszczania system wyświetla obraz, który użytkownik przeciąga. W przypadku przenoszenia danych ten obraz reprezentuje przeciągane dane. W przypadku innych operacji obraz reprezentuje pewien aspekt operacji przeciągania.
Obraz nazywa się cieniem przeciągania. Tworzysz go za pomocą metod zadeklarowanych dla
a
View.DragShadowBuilder
obiektu. Przekazujesz konstruktora do systemu, gdy rozpoczynasz operację przeciągania i upuszczania za pomocą startDragAndDrop(). 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 dowolny obiekt aplikacji
View. Konstruktor przechowuje obiektVieww obiekcieView.DragShadowBuilder, dzięki czemu wywołania zwrotne mogą uzyskać do niego dostęp, aby utworzyć cień przeciągania. Widok nie musi byćView, który użytkownik wybiera, aby rozpocząć operację przeciągania.Jeśli używasz tego konstruktora, nie musisz rozszerzać
View.DragShadowBuilderani zastępować jego metod. Domyślnie otrzymujesz cień przeciągania, który ma taki sam wygląd jakViewprzekazywany jako argument, wyśrodkowany pod lokalizacją, w której użytkownik dotyka ekranu.View.DragShadowBuilder()Jeśli używasz tego konstruktora, w obiekcie
View.DragShadowBuildernie jest dostępny żaden obiektView. Pole jest ustawione nanull. Musisz rozszerzyćView.DragShadowBuilderi zastąpić jego metody, w przeciwnym razie otrzymasz niewidoczny cień przeciągania. 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
startDragAndDrop(). Użyj tej metody, aby wysłać do systemu wymiary i punkt dotyku cienia przeciągania. Metoda ma 2 parametry:outShadowSize: obiektPoint. Szerokość cienia przeciągania jest podawana wx, a jego wysokość wy.outShadowTouchPoint: obiektPoint. Punkt dotyku to miejsce w cieniu przeciągania, które musi znajdować się pod palcem użytkownika podczas przeciągania. Jego pozycja X jest podawana wx, a pozycja Y wy.onDrawShadow()Natychmiast po wywołaniu
onProvideShadowMetrics()system wywołujeonDrawShadow(), 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 podanymCanvas.
Aby zwiększyć wydajność, zmniejsz rozmiar cienia przeciągania. W przypadku pojedynczego elementu możesz użyć ikony. W przypadku zaznaczenia wielu elementów możesz użyć ikon w stosie zamiast pełnych obrazów rozłożonych na ekranie.
Detektory zdarzeń przeciągnięcia i metody wywołania zwrotnego
A View odbiera zdarzenia przeciągnięcia za pomocą detektora zdarzeń przeciągnięcia, który implementuje
View.OnDragListener lub za pomocą metody wywołania zwrotnego onDragEvent() widoku. Gdy
system wywołuje metodę lub detektor, przekazuje
DragEvent argument.
W większości przypadków lepiej jest używać detektora niż metody wywołania zwrotnego. Podczas projektowania interfejsów zwykle nie tworzysz podklas klas View, ale użycie metody wywołania zwrotnego wymusza utworzenie podklas w celu zastąpienia metody. W porównaniu z tym możesz zaimplementować 1 klasę detektora, a następnie używać jej z wieloma różnymi obiektami View. Możesz też zaimplementować ją jako anonimową klasę wbudowaną lub wyrażenie lambda. Aby ustawić detektor dla obiektu View, wywołaj setOnDragListener().
Alternatywnie możesz zmienić domyślną implementację onDragEvent() bez zastępowania metody. Ustaw
OnReceiveContentListener
w widoku. Więcej informacji znajdziesz w artykule
setOnReceiveContentListener().
Metoda onDragEvent() domyślnie wykonuje te czynności:
- Zwraca wartość true w odpowiedzi na wywołanie
startDragAndDrop(). Wywołuje
performReceiveContent(), jeśli dane przeciągania i upuszczania zostaną upuszczone w widoku. Dane są przekazywane do metody jakoContentInfoobiekt. Metoda wywołujeOnReceiveContentListener.Zwraca wartość true, jeśli dane przeciągania i upuszczania zostaną upuszczone w widoku, a
OnReceiveContentListenerwykorzysta część treści.
Zdefiniuj OnReceiveContentListener, aby obsługiwać dane konkretnie w swojej
aplikacji. Aby zapewnić zgodność wsteczną z poziomem API 24, użyj wersji Jetpack
OnReceiveContentListener.
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 wywołania zwrotnego, chyba że detektor zwróci wartość false.
Połączenie metody onDragEvent() i View.OnDragListener jest
analogiczne do połączenia
onTouchEvent()
i View.OnTouchListener
używanego w przypadku zdarzeń dotykowych.