[swift] RxDataSources를 사용한 컬렉션 뷰의 드래그 앤 드롭 처리 방법

이번 블로그 포스트에서는 RxDataSources를 사용하여 iOS 앱에서 컬렉션 뷰의 드래그 앤 드롭 기능을 구현하는 방법에 대해 알아보겠습니다.

목차

  1. RxDataSources란?
  2. 컬렉션 뷰 설정
  3. 드래그 앤 드롭 구현
  4. 결론

RxDataSources란?

RxDataSources는 RxSwift와 결합되어 데이터 소스를 관리하는 편리한 도구입니다. 이를 통해 리액티브한 방식으로 컬렉션 뷰나 테이블 뷰의 데이터를 관리할 수 있습니다.

컬렉션 뷰 설정

드래그 앤 드롭을 구현하기 전에 먼저 컬렉션 뷰를 설정해야 합니다.

// 컬렉션 뷰 설정
func setupCollectionView() {
    collectionView.dragInteractionEnabled = true
    collectionView.dragDelegate = self
    collectionView.dropDelegate = self
}

드래그 앤 드롭을 활성화하려면 dragInteractionEnabled 속성을 true로 설정해야 합니다. 그리고 dragDelegatedropDelegate를 설정하여 드래그 앤 드롭 이벤트를 처리할 수 있습니다.

드래그 앤 드롭 구현

RxDataSources를 사용하여 컬렉션 뷰에서 드래그 앤 드롭을 구현하는 방법은 다음과 같습니다.

  1. Drag and Drop을 위한 Gesture Recognizer 추가
collectionView.rx.dragDelegate()
    .disposed(by: disposeBag)

collectionView.rx.dropDelegate()
    .disposed(by: disposeBag)
  1. 드래그 시작 시 데이터 소스를 업데이트하는 방법 정의
func dragItems(at indexPath: IndexPath) -> [UIDragItem] {
    guard let item = collectionView.dataSource?[indexPath.item] else { return [] }
    let itemProvider = NSItemProvider(object: item)
    let dragItem = UIDragItem(itemProvider: itemProvider)
    dragItem.localObject = item
    return [dragItem]
}

collectionView.rx.dragItemsForBeginning(at: { [weak self] indexPath in
    return self?.dragItems(at: indexPath) ?? []
})
    .asDriver(onErrorJustReturn: [])
    .drive(onNext: { [weak self] items in
        self?.draggedItems = items
    })
    .disposed(by: disposeBag)
  1. 드롭이 허용되는 경우 데이터 소스를 업데이트하는 방법 정의
collectionView.rx.dropDelegate().performDropWithCoordinator = { [weak self] coordinator in
    guard let self = self else { return }
    
    let destinationIndexPath: IndexPath
    
    if let indexPath = coordinator.destinationIndexPath {
        destinationIndexPath = indexPath
    } else {
        let section = self.collectionView.numberOfSections - 1
        let row = self.collectionView.numberOfItems(inSection: section)
        destinationIndexPath = IndexPath(row: row, section: section)
    }
    
    coordinator.session.loadObjects(ofClass: YourDataType.self) { items in
        let item = items.first as? YourDataType
        // 드롭된 아이템에 대한 처리
        // 데이터 소스 업데이트 등
    }
}
  1. 데이터 소스에 대한 변경 사항을 컬렉션 뷰에 반영하는 방법
let dataSource = RxCollectionViewSectionedReloadDataSource<YourSectionModelType>(
    configureCell: { dataSource, collectionView, indexPath, item in
        // 셀 구성
    },
    configureSupplementaryView: { dataSource, collectionView, kind, indexPath in
        // 보조 뷰 구성
    })

// 데이터 소스 변경 반영
viewModel.items
    .bind(to: collectionView.rx.items(dataSource: dataSource))
    .disposed(by: disposeBag)

결론

RxDataSources와 함께 사용하면 쉽게 컬렉션 뷰의 드래그 앤 드롭을 구현할 수 있습니다. 드래그와 드롭을 위한 Gesture Recognizer를 추가하고, 드래그/드롭 이벤트에 대한 처리 방식을 정의한 후, 데이터 소스에 대한 변경을 컬렉션 뷰에 반영하면 됩니다. 이를 통해 iOS 앱에서 경량하고 반응적인 드래그 앤 드롭 기능을 구현할 수 있습니다.

참고 자료