以下各節將說明拖曳程序的幾個重要概念。
拖曳程序
拖曳過程有四個步驟或狀態:開始、繼續、放置和結束。
- 已開始
為回應使用者的拖曳手勢,應用程式會呼叫
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 的說明:
表 1. DragEvent 動作類型
動作類型 | 意義 |
---|---|
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 所列。如要進一步瞭解事件及其相關資料,請參閱「拖曳作業」一節。
表 2. 各動作類型的有效 DragEvent 資料
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()
來建立拖曳陰影。此方法有一個引數,即系統使用您在onProvideShadowMetrics()
中提供的參數建構的Canvas
物件。此方法會在提供的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
組合。