다음 섹션에서는 드래그 앤 드롭 프로세스의 몇 가지 주요 개념을 설명합니다.
드래그 앤 드롭 프로세스
드래그 앤 드롭 프로세스에는 시작, 계속, 삭제, 종료됨과 같은 4가지 단계 또는 상태가 있습니다.
- 시작됨
사용자의 드래그 동작에 대한 응답으로 애플리케이션은
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
클래스의 상수로 정의된 6개의 값을 사용할 수 있으며, 각 값은 표 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 위에 놓입니다. 이 작업 유형은 리스너가 ACTION_DRAG_STARTED 드래그 이벤트에 대한 응답으로 불리언 true 를 반환하는 경우에만 View 객체의 리스너로 전송됩니다. 사용자가 리스너가 등록되지 않은 View 위에 드래그 섀도우를 놓거나 현재 레이아웃에 포함되지 않은 항목 위에 드래그 섀도우를 놓는 경우에는 이 작업 유형이 전송되지 않습니다.
드롭이 정상적으로 처리되면 리스너는 불리언 |
ACTION_DRAG_ENDED |
시스템에서 드래그 앤 드롭 작업을 종료합니다. 이 작업 유형이 반드시 ACTION_DROP 이벤트 다음에 발생하는 것은 아닙니다. 시스템에서 ACTION_DROP 를 전송하면 ACTION_DRAG_ENDED 작업 유형을 수신한다고 해서 드롭이 성공했음을 의미하지는 않습니다. 리스너에서는 표 2와 같이 getResult() 를 호출하여 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
객체에 사용할 수 있습니다.
익명 인라인 클래스 또는 람다 표현식으로 구현할 수도 있습니다. View
객체의 리스너를 설정하려면 setOnDragListener()
를 호출합니다.
또는 메서드를 재정의하지 않고 onDragEvent()
의 기본 구현을 변경할 수 있습니다. 뷰에서 OnReceiveContentListener
를 설정합니다. 자세한 내용은 setOnReceiveContentListener()
를 참고하세요.
그러면 onDragEvent()
메서드는 기본적으로 다음을 실행합니다.
startDragAndDrop()
호출에 대한 응답으로 true를 반환합니다.드래그 앤 드롭 데이터가 뷰에 드롭되면
performReceiveContent()
를 호출합니다. 데이터는ContentInfo
객체로 메서드에 전달됩니다. 이 메서드는OnReceiveContentListener
를 호출합니다.드래그 앤 드롭 데이터가 뷰에 드롭되고
OnReceiveContentListener
가 콘텐츠를 사용하는 경우 true를 반환합니다.
앱에 맞게 데이터를 처리하도록 OnReceiveContentListener
를 정의합니다. API 수준 24까지의 하위 호환성을 위해 Jetpack 버전의 OnReceiveContentListener
를 사용합니다.
드래그 이벤트 리스너와 View
객체의 콜백 메서드를 보유할 수 있습니다. 이 경우 시스템에서 리스너를 먼저 호출합니다. 리스너가 false
를 반환하지 않는 한 시스템은 콜백 메서드를 호출하지 않습니다.
onDragEvent()
메서드와 View.OnDragListener
를 함께 사용하는 것은 터치 이벤트에 사용되는 onTouchEvent()
와 View.OnTouchListener
의 조합과 유사합니다.