같은 앱의 일 경우 해당 앱이 드래그의 source app
그리고 destination app
이 됩니다!
TableView의 drag 와 drop 기능을 지원하게 하려면 먼저 ViewController에게 UITableViewDragDelegate
프로토콜을 채택하게 한 뒤
override func viewDidLoad() {
super.viewDidLoad()
tableView.dragInteractionEnabled = true
tableView.dragDelegate = self
tableView.dropDelegate = self
}
위와 같이 드래깅 상호작용을 가능하게 설정한 뒤 dragDelegate
와 dropDelegate
에게 viewcontroller 자신을 할당 해 주어야 합니다.
tableView(_:itemsForBeginning:at:)
유저의 드래깅 제스처가 발생 되면, TableView는 drag session 을 생성 한 뒤 tableView(_:itemsForBeginning:at:)
매서드를 호출합니다.(만약 유저가 특정한 cell을 drag 할 시 해당 메서드는 선택시에 한 번만 호출 되고 어떤 cell도 선택되지 않는다면 해당 메서드는 단 한 번만 호출 됩니다.) 만약 반환 값이 빈 배열이 아니라면, tableview는 사용자가 명시한 cell을 drag 하기 시작합니다. 만약 특정한 index path로 부터 사용자가 컨텐츠를 드래그하는 것을 방지하려면 빈 배열을 반환하도록 하여야 합니다.
tableView(_:itemForBeginning:at:)
메서드 속에서는 아래와 같은 작업이 필요합니다.
NSItemProvider
를 생성한 뒤 이를 활용하여 table의 행의 데이터를 표시하도록 사용하세요.UIDragItem
으로 감싸 주어야 합니다.localObject
프로퍼티에게 값을 할당하는 것을 고려 해 주세요. 이 과정은 필수는 아니지만 동일한 앱 속의 컨텐츠를 드래그하고 드랍하는 속도를 더 빠르게 합니다.제공된 indexPath
를 사용하여 드래그 항목을 생성할 행을 결정합니다. 만약 대상 행이 현재 선택된 행 중 하나인 경우 tableview는 선택된 모든 행을 드래그 합니다. 만약 선택되지 않았던 행인 경우 드래그 작업에 해당 행을 추가합니다.
Use a drag items to convey data representation promises between a source app and a destination app.
사용자가 사진, 지도, 캘린더일정, 또는 선택된 텍스트를 드래그하면, 사용자의 앱은 드래그한 파일의 기본데이터를 drag item
으로 연결 시켜 줍니다.
drag item은 이어지는 작업으로 itemProvider
를 활용합니다.
사용자 앱은 itemProvider의 registeredTypeIdentifiers
array와 uniform type identifiers(UTIs)
를 제공합니다.
item provider의 type identifier 배열을 반환 해 줍니다. 이 배열에 있는 type identifier들은 등록된 순서대로 배열에 담겨져 있습니다.
registeredtypeIdentifiers | Apple Developer Document
uniform type identifer(UTI)는 개체의 클래스를 타입별로 구별 해주는 문자열입니다. UTI는 보통 파일의 포멧 또는 인메모리 데이터 타입을 식별할 때 사용되고 디렉토리, 데이터볼륨, 또는 패키지의 계층적 레이아웃을 감별할 때도 사용됩니다. 예를 들면 Iphone의 앱은 UITs를 사용해서 클립보드에 복사할 수 있는 데이터의 포맷을 정의합니다. Mac 앱은 UTI를 활용하여 앱이 열 수 있는 파일의 타입을 정의합니다.
Uniform Type Identifier | Cocoa Core Competencies
UTI 배열에서는 발송자 앱이 목적지엡에 보낼 수 있는 특정한 데이터 표현에 대한 약속이 구성되어 있습니다. 여기서 약속(promise)이란 사용자 앱이 drag item을 구성할 때 앱이 특정한 데이터 표현으로 데이터를 제공하겠다는 것을 약속하는 것입니다.
DragItem은 data의 표현을 제공할 뿐 data 자체를 만드는 것이 아닙니다.
사용자가 특정 컨텐츠를 드래그 했을 때 사용자가 느끼기에는 컨텐츠 데이터를 가지고 전달하는 것 처럼 보일 수 있지만 사실은 이 드래그한 item은 사용자가 가지고 가는 컨텐츠의 preview image와 itemprovider가 구성한 이 약속이 드래그된 item에 포함이 되는 것입니다.
TableView, CollectionView가 아닌 Custom View에서 사용할 때:
발송하는 앱의 에서는 UIDragInteractionDeleagate
가 drag item을 구성 해 줍니다.
목적지 앱에서는 UIDropInteractionDelegate
가 drag item과 상호작용하여 약속된 데이터를 사용합니다.
tableView(_:canHandle:)
드래그된 컨텐츠가 범위 안에 들어오면 tableview는 dropDelegate
와 상의 후 드래그된 데이터를 받을 수 있는지 없는지 결정합니다.
첫 째로 tableView는 tableView(_:canHandle:)
메서드를 호출하여 드래그된 데이터를 받는 개체의 datasource에 추가될 수 있는지 확인합니다.
canLoadObjects(ofClass:)
tableView(_:dropSessionDidUpdate:withDestinationIndexPath:)
유저가 드래그 된 개체를 손가락으로 움직이면 tableView는 잠재적 drop 위치를 추적하고 추적하는 정보를 지속적으로 tableView(_:dropSessionDidUpdate:withDestinationIndexPath:)
메서드를 통해 dropDelegate
에게 정보를 전달합니다. 해당 작업은 선택사항이지만 권고하는 작업입니다. 왜냐하면 tableView가 드롭관련한 시각적 효과를 줄 수 있게하기 때문입니다.
위 메서드를 구현할 때 UITableViewDropProposal
개채를 특정한 indexpath에 드랍 했을 때 어떻게 응답할 것인지에 대한 정보를 포함하여 생성해야합니다.
dropSessionDidUpdate:withDestinationIndexPath
메서드는 유저가 drag하는 동안 반복적으로 매우 자주 호출 되기 때문에 proposal을 될 수 있으면 빠르게 반환 해 주어야 합니다.
tableView(_:performDropWith:)
사용자가 드랍을 끝낸 뒤 손가락을 화면에서 때면, tableView는 tableView(_:performDropWith:)
메서드를 호출합니다. 해당 메서드를 활용하여 드랍된 데이터를 처리해주어야 합니다.
해당 메서드를 구현할 때 드래그된 데이터를 불러와야하고 드랍된 tableView의 datasource를 업데이트 해 주어야 하고 tableView에 필요한 행을 추가 해 주어야 합니다.
*만약 드래그된 컨텐츠가 tableView로부터 온 것이라면 API를 활용하여 기존 위치의 행을 지우고 새로운 위치에 행을 추가할 수 있습니다.
만약 tableView 밖으로부터 온 컨텐츠라면 같은 앱 간의 이동이라면 localObject
프로퍼티를 활용할 수 있고 다른 앱으로 부터 온 컨텐츠라면 NSItemProvider
를 활용하여 데이터를 가져오고 데이터를 집어넣을 수 있습니다.
(_:performDropWith:)
메서드를 사용할 때 아래와 같은 작업이 필요합니다:
drop coordinator object
의 item 프로퍼티를 순회하여야 합니다.batchUpdate
를 활용하여 기존 위치의 item을 제거하고 새로운 indexpath에 해당 item을 추가해야합니다.localObject
프로퍼티가 제공된다면 해당 item은 동일 앱내 다른 곳에서 온 컨텐츠이기 때문에 행을 추가 해 주거나 item을 업데이트 시켜줘야합니다.NSItemProvider
프로퍼티를 활용하여 데이터를 비동기적으로 불러오고 item을 삽입하거나 업데이트해야합니다.datasource
를 업데이트 하거나 필요한 item을 tableView 내에서 삽입 또는 이동시켜주어야 합니다.드래깅을 사용하고자 하는 앱 속에 있는 컨텐츠라면 대부분 tableView의 datasource를 직접적으로 업데이트할 수 있습니다. 예를 들면 batchupdate를 활용하여 행을 제거한 뒤 새로 삽입할 수 있습니다. 해당 작업이 끝난 뒤
drop(_:toRowAt:)
메서드를 호출하여 drop coordinator가 행이 더해지는 애니메이션효과를 줄 수 있습니다.
외부 또는 다른 앱으로 밭는 데이터인 경우 NSItemProvider
개체를 활용하여 데이터를 받아야합니다. 새로운 행을 tableView로 추가하려면 placeholder
를 구현 해 주어야 합니다. placeholder
는 실제데이터가 완전히 전달되기 전까지 유저에게 잠시동안 보여지는 행 역할을 합니다. 예를 들면 로딩중이라는 placeholder
를 추가해서 컨텐츠가 특정 행으로 추가되고 있다는 것을 보여줄 수 있습니다.
placeholder
를 추가하려면 아래와 같은 작업을 해야합니다:
drop(_:toPlaceholderInsertedAt:withReuseIdentifier:rowHeight:cellUpdateHandler:_)
를 활용하여 placeholder를 행으로 추가할 수 있습니다. cellUpdateHanlder
파라메터에 코드블럭을 활용하여 placeholder의 컨텐츠를 세팅할 수 있습니다.NSItemProvider
개체로부터 데이터를 비동기적으로 받아와야합니다.NSItemProvider
개체가 실제 데이터를 반환하면 데이터를 삽입한 뒤 placeholder cell을 받아온 데이터 cell로 바꿔줍니다. 구체적으로 commitInsertion(dataSourceUpdates:)
메서드를 호출해서 위 작업을 하면 됩니다. 해당 메서드의 블럭 안에서 모델을 업데이트하고 tableView의 datasource를 업데이트하면 됩니다. 해당 메서드가 반환되면 tableview는 자동적으로 placeholder
를 제거하고 필요한 데이터를 가진 행을 추가합니다. 이 업데이트는 drop coordinator가 위치로 정한 indexpath(destinationIndexPath)에서 이뤄집니다.
[출처]:
Supporting Drag and Drop in TableViews | Apple Developer Document
The item provider associated with the drag item
var itemProvider: NSItemProvider { get }
item provider는 드래그 앤 드랍 과정에서 데이터 또는 파일을 전달하는 역할을 담당합니다. 해당 프로퍼티는 UIDragItem instance가 생성될 때 UIDragItem의 init(itemProvider:)
를 통해 특정한 item Provider로 세팅이 될 수 있습니다.
itemProvider | Apple Developer Document
A custom object associated with the drag item
Local object 프로퍼티는 model object와 같은 커스텀 object를 drag item에 결부(connect)시킬 수 있는 옵션을 제공합니다. 드래그가 활성화 된 앱에서만 해당 object를 활용할 수 있습니다.
drag session과 drop sesstion의 상태를 조회하기 위한 인터페이스입니다.
UIDragDropSession | Apple Developer Document
An interface for coordinating your custom drop-related actions with the table view.
아이템을 드래그해서 드랍 할 때 취해야 할 행위를 지정해주는 인터페이스입니다.
[UITableViewDropCoordinator | Apple Developer Document](