TableView 에서 드래그드롭 기능을 구현해보자
테이블 뷰내에서 드래그 앤 드롭기능을 구현해보려고 여러 문서를 보면서 공부를 해보았습니다!
알아보니 테이블 뷰에 드래그 드롭 API가 존재하더라구요 ,,,친절도해라...
바로 UITableViewDragDelegate 요놈입니다!
이 API 를 사용하면 다른 앱간의 드래그 앤 드랍까지 가능합니다 (달달하네요)
이 프로토콜을 채택한 객체의 프로퍼티
•
dragDelegate
•
dropDelegate
들을 사용해서 드래그 앤 드롭 기능을 구현해 볼거에요 ㅎ
이 두 프로토콜을 준수함으로서 드래그앤 드롭 기능을 구현할 수 있어요!
설명 시작해 보겠습니다
드래그앤 드롭 기능 활성화하기
먼저 테이블 뷰 컨트롤러 자신을 tableView 의 dropDelegate dragDelegate 프로퍼티에 할당해줍시다 ㅎ
override func viewDidLoad() {
super.viewDidLoad()
tableView.dragInteractionEnabled = true
tableView.dragDelegate = self
tableView.dropDelegate = self
navigationItem.rightBarButtonItem = editButtonItem
}
Swift
복사
드래그 세션에 데이터 제공하기
드래그 하고자 하는 행의 데이터를 드래그 세션에 건네주어야 한답니다!
1.
모델에 헬퍼 메서드 정의하기
// model.swift
func dragItems(for indexPath: IndexPath) -> [UIDragItem] {
let 데이터 = 데이터들[indexPath.row]
let data = 데이터객체.data(using: .utf8) //스트링 타입 데이터 인코딩하기
//프로세스간 데이터 전달 객체 생성
// 이객체는 프로세스들 간의 드래그 앤 드롭 활동사이에서 데이터의 공유를 수행합니다.
let itemProvider = NSItemProvider()
itemProvider.registerDataRepresentation(forTypeIdentifier: kUTTypePlainText as String, visibility: .all) { completion in
//객체가 성공적으로 생성되면 data 등록
completion(data, nil)
return nil
}
return [
//드래그할 항목을 아이템 프로바이더 객체와 함꼐 생성 및 리턴
UIDragItem(itemProvider: itemProvider)
]
}
Swift
복사
2.
드래그 세션에 데이터 제공하기
// 세션에 데이터 제공
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
return model.dragItems(for: indexPath)
}
Swift
복사
드래그 세션으로 부터 데이터 가져오기
드랍할 때 드래그 세션으로부터 데이터를 가져와 사용하게됩니다!
1.
모델에 헬퍼 메서드 정의하기
// model.swift
func canHandle(_ session: UIDropSession) -> Bool {
return session.canLoadObjects(ofClass: NSString.self)
}
Swift
복사
canLoadObjects(ofClass:) 이 메서드는 부울 값을 리턴합니다.
•
true : 드래그 세션 내의 항목중 적어도 하나는 특정 클래스의 인스턴스를 생성할 수 있을 때,
•
false : 드래그 세션에 어떠한 항목도 인스턴스를 생성할 수 없을 때
2.
드래그 세션으로 부터 데이터 가져오기
위에서 정의한 메서드에 session 객체를 전달해줍니다!
//TableViewController.swift
func tableView(_ tableView: UITableView, canHandle session: UIDropSession) -> Bool {
return model.canHandle(session)
}
Swift
복사
3.
시스템에게 데이터를 어떻게 사용하고자 하는지 명시해주기
//TableViewController.swift
func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
var dropProposal = UITableViewDropProposal(operation: .cancel)
// 한번에 하나의 드래그 아이템 만 허용
guard session.items.count == 1 else { return dropProposal }
//is edit mode 일 때만 드래그 가능.
if tableView.hasActiveDrag {
if tableView.isEditing {
dropProposal = UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
} else {
// 앱 바깥에서의 드래그.
dropProposal = UITableViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)
}
return dropProposal
}
Swift
복사
4.
사용자가 화면에서 손을 떼면, 테이블 뷰는 자신의 content 를 수정하도록 해주기
//TableViewController.swift
func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
let destinationIndexPath: IndexPath
// 드랍한 위치의 인덱스 받아오기
if let indexPath = coordinator.destinationIndexPath {
destinationIndexPath = indexPath
} else {
// 드랍한 위치가 테이블 뷰 밖이라면??
//테이블 뷰 맨 아래의 인덱스 가져오기
let section = tableView.numberOfSections - 1
let row = tableView.numberOfRows(inSection: section)
destinationIndexPath = IndexPath(row: row, section: section)
}
//세션에서 객체 가져오기
coordinator.session.loadObjects(ofClass: NSString.self) { items in
// 항목 소비하기
//세션에서 가져온 객체들을 문자열로 타입캐스팅
let stringItems = items as! [String]
var indexPaths = [IndexPath]()
for (index, item) in stringItems.enumerated() {
let indexPath = IndexPath(row: destinationIndexPath.row + index, section: destinationIndexPath.section)
self.model.addItem(item, at: indexPath.row)
indexPaths.append(indexPath)
}
tableView.insertRows(at: indexPaths, with: .automatic)
}
}
Swift
복사