以下各節說明拖曳程序的幾個重要概念。
拖曳程序
拖曳程序有四個步驟或狀態:已開始、執行、捨棄和結束。
- 已開始
為回應使用者的拖曳手勢,應用程式會呼叫
startDragAndDrop()
以指示系統開始拖曳作業。方法的引數提供以下內容:- 要拖曳的資料。
- 用於繪製拖曳陰影的回呼
- 描述拖曳資料的中繼資料
- 系統回應時,系統會呼叫應用程式以取得拖曳陰影。然後在裝置上顯示拖曳陰影。
- 接著,系統會將動作類型為
ACTION_DRAG_STARTED
的拖曳事件傳送至目前版面配置中所有View
物件的拖曳事件監聽器。如要繼續接收拖曳事件 (包括可能的放置事件),拖曳事件監聽器必須回傳true
。此指令會向系統註冊事件監聽器。只有已註冊的事件監聽器會繼續接收拖曳事件。此時,事件監聽器也可以變更放置目標View
物件的外觀,以表示檢視畫面能夠接受放置事件。 - 如果拖曳事件監聽器回傳
false
,將不會收到目前作業的拖曳事件,直到系統傳送動作類型為ACTION_DRAG_ENDED
的拖曳事件。事件監聽器會藉由回傳false
,向系統表示不想參與拖曳作業,且不想接受拖曳的資料。
- 繼續
- 使用者繼續拖曳。當拖曳陰影與放置目標的定界框交會時,系統會傳送一或多個拖曳事件至目標的拖曳事件監聽器。事件監聽器可能會依據事件變更放置目標
View
的外觀。舉例來說,如果事件指出拖曳陰影進入放置目標的定界框 (動作類型ACTION_DRAG_ENTERED
),事件監聽器就會醒目顯示View
。 - 已拖曳
- 使用者在放置目標的定界框內放開拖曳陰影。系統會向放置目標的事件監聽器傳送動作類型為
ACTION_DROP
的拖曳事件。拖曳事件物件包含在開始作業的startDragAndDrop()
呼叫中傳遞給系統的資料。如果事件監聽器成功處理放置的資料,事件監聽器應將布林值true
傳回系統。:只有在使用者將拖曳陰影拖曳到已經過註冊而得以接收拖曳事件的View
(放置目標) 定界框中時,系統才會執行這個步驟。如果使用者在任何其他情況下放開拖曳陰影,系統就不會傳送ACTION_DROP
拖曳事件。 - 已結束
使用者放開拖曳陰影,且系統傳送
視需要傳送動作類型為
ACTION_DROP
的拖曳事件,系統會傳送動作類型為ACTION_DRAG_ENDED
的拖曳事件,表示拖曳作業已結束。無論使用者放開拖曳陰影的位置為何。即使事件監聽器收到ACTION_DROP
事件,系統仍會將事件傳送給每個註冊接收拖曳事件的事件監聽器。
如要進一步瞭解這些步驟,請參閱「拖曳作業」一節。
拖曳事件
系統會以 DragEvent
物件的形式傳送拖曳事件,其中包含描述拖曳過程的動作類型。視動作類型而定,物件中也可能包含其他資料。
拖曳事件監聽器會接收 DragEvent
物件。為了取得動作類型,事件監聽器會呼叫 DragEvent.getAction()
。DragEvent
類別中的常數定義了六個可能的值,如表 1 所述:
動作類型 | 意義 |
---|---|
ACTION_DRAG_STARTED |
應用程式會呼叫 startDragAndDrop() 並取得拖曳陰影。如果事件監聽器要繼續接收此作業的拖曳事件,則必須將布林值 true 回傳系統。 |
ACTION_DRAG_ENTERED |
拖曳陰影會進入拖曳事件監聽器 View 的定界框。這是拖曳陰影進入定界框時,事件監聽器收到的第一個事件動作類型。 |
ACTION_DRAG_LOCATION |
在 ACTION_DRAG_ENTERED 事件之後,拖曳陰影仍位於拖曳事件監聽器 View 的定界框內。 |
ACTION_DRAG_EXITED |
在 ACTION_DRAG_ENTERED 和至少一個 ACTION_DRAG_LOCATION 事件之後,拖曳陰影會移動至拖曳事件監聽器 View 的定界框外。 |
ACTION_DROP |
拖曳陰影會在拖曳事件監聽器的 View 上放開。只有在事件監聽器回傳布林值 true 以回應 ACTION_DRAG_STARTED 拖曳事件時,系統才會將動作類型傳送至 View 物件的事件監聽器。如果使用者在未註冊事件監聽器的 View 上放開拖曳陰影,或在不屬於目前版面配置的任一處放開,就不會傳送此動作類型。
如果成功處理放置,事件監聽器會傳回布林值 |
ACTION_DRAG_ENDED |
系統即將結束拖曳作業。動作類型不一定要在 ACTION_DROP 事件前面。如果系統傳送 ACTION_DROP ,即使收到 ACTION_DRAG_ENDED 動作類型,也不代表拖曳成功。事件監聽器必須呼叫 getResult() (如表 2 所示) 以取得回應 ACTION_DROP 時回傳的值。如未傳送 ACTION_DROP 事件,則 getResult() 會回傳 false 。 |
DragEvent
物件也會包含應用程式在呼叫 startDragAndDrop()
時提供給系統的資料和中繼資料。有些資料僅適用於特定動作類型,如表 2 所列。如要進一步瞭解事件及相關資料,請參閱「拖曳作業」一節。
getAction() 價值 |
getClipDescription() 價值 |
getLocalState() 價值 |
getX() 價值 |
getY() 價值 |
getClipData() 價值 |
getResult() 價值 |
---|---|---|---|---|---|---|
ACTION_DRAG_STARTED |
✓ | ✓ | ||||
ACTION_DRAG_ENTERED |
✓ | ✓ | ||||
ACTION_DRAG_LOCATION |
✓ | ✓ | ✓ | ✓ | ||
ACTION_DRAG_EXITED |
✓ | ✓ | ||||
ACTION_DROP |
✓ | ✓ | ✓ | ✓ | ✓ | |
ACTION_DRAG_ENDED |
✓ | ✓ |
DragEvent
方法 getAction()
、describeContents()
、writeToParcel()
和 toString()
一律會傳回有效資料。
如果方法未包含特定動作類型的有效資料,系統會根據其結果類型傳回 null
或 0。
拖曳陰影
在拖曳作業期間,系統會顯示使用者拖曳的圖片。若是移動資料,此圖片則代表拖曳的資料。若是其他作業,圖片則代表拖曳作業的某些部分。
此圖片稱為「拖曳陰影」。請使用您為 View.DragShadowBuilder
物件宣告的方法建立。使用 startDragAndDrop()
啟動拖曳作業時,會將建構工具傳遞至系統。為回應 startDragAndDrop()
,系統會叫用您在 View.DragShadowBuilder
中定義的回呼方法,藉此取得拖曳陰影。
View.DragShadowBuilder
類別有兩個建構函式:
View.DragShadowBuilder(View)
此建構函式接受應用程式的任何
View
物件。建構函式會將View
物件儲存在View.DragShadowBuilder
物件中,因此回呼可以存取該物件來建構拖曳陰影。檢視畫面不一定要是使用者為了開始作業而選取的View
。使用此建構函式時,您不必擴充
View.DragShadowBuilder
或覆寫其方法。根據預設,拖曳陰影的外觀會與做為引數傳遞的View
相同,並位於使用者輕觸螢幕的位置下方。View.DragShadowBuilder()
如果使用此建構函式,
View.DragShadowBuilder
物件中就不會有View
物件。這個欄位已設為null
。您必須擴充View.DragShadowBuilder
並覆寫其方法,否則會發生看不到的拖曳陰影。系統不會擲回錯誤。
View.DragShadowBuilder
類別有兩個方法共同建立拖曳陰影:
onProvideShadowMetrics()
當您呼叫
startDragAndDrop()
後,系統會立即呼叫此方法。此方法會將拖曳陰影的維度和觸控點傳送到系統。此方法有兩個參數:outShadowSize
:Point
物件。拖曳陰影寬度為x
,高度為y
。outShadowTouchPoint
:Point
物件。觸控點是指拖曳陰影內的位置,拖曳時必須位在使用者手指下方。其「X」位置位於x
,Y 位置則為y
。onDrawShadow()
呼叫
onProvideShadowMetrics()
後,系統會立即呼叫onDrawShadow()
來建立拖曳陰影。此方法有一個引數,即Canvas
物件,系統會根據您在onProvideShadowMetrics()
中提供的參數建構。此方法會在提供的Canvas
上繪製拖曳陰影。
為提升效能,請盡量使用較小的拖曳陰影。如果是單一項目,建議您使用圖示。如果需要選擇多個項目,建議您使用堆疊中的圖示,而不要將整個圖片蓋滿螢幕畫面。
拖曳事件監聽器和回呼方法
View
收到的拖曳事件可能包含實作 View.OnDragListener
的拖曳事件監聽器,或利用檢視畫面的 onDragEvent()
回呼方法。當系統呼叫方法或事件監聽器時,會提供 DragEvent
引數。
在大部分情況下,使用監聽器時最好使用回呼方法。設計 UI 時,您通常不會將 View
類別設為子類別,不過如果您使用回呼方法,則必須建立子類別來覆寫此方法。相較之下,您可以導入一個事件監聽器類別,然後搭配多個不同的 View
物件使用。您也可以將此實作為匿名內嵌類別或 lambda 運算式。如要設定 View
物件的事件監聽器,請呼叫 setOnDragListener()
。
或者,您也可以在不覆寫該方法的情況下,修改 onDragEvent()
的預設實作方式。在檢視區塊上設定 OnReceiveContentListener
;詳情請參閱 setOnReceiveContentListener()
。根據預設,onDragEvent()
方法會執行以下操作:
- 回傳 true 值以回應對
startDragAndDrop()
的呼叫。 如果拖曳資料在檢視畫面上放置,系統會呼叫
performReceiveContent()
。資料會以ContentInfo
物件的形式傳遞至方法。此方法會叫用OnReceiveContentListener
。如果拖放資料在檢視畫面上放置,且
OnReceiveContentListener
會使用任何內容,則會回傳 true。
定義 OnReceiveContentListener
以專門處理應用程式的資料。為了回溯相容到 API 級別 24,請使用 OnReceiveContentListener
的 Jetpack 版本。
您可以為 View
物件設定拖曳事件監聽器和回呼方法。在此情況下,系統會先呼叫事件監聽器。除非監聽器回傳 false
,否則系統不會呼叫回呼方法。
onDragEvent()
方法和 View.OnDragListener
的組合類似觸控事件使用的 onTouchEvent()
和 View.OnTouchListener
。