Search
🤏🏻

UITableView 에서 drag and drop 기능 구현하기

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
복사