DragAndDropKit-iOS15下一行代碼集成跨應用間拖拽傳遞數據

語言: CN / TW / HK

前言

前段時間蘋果剛推出了iOS15正式版,我也是第一時間就升級了體驗。期間體驗到了一個非常有趣的交互如下視頻。

如視頻所示,iOS15下的蘋果系統相冊支持將圖片、視頻,文本等直接拖拽複製到其他應用(目前親測自帶備忘錄、騰訊QQ等是支持的)。作為一個iOS工程師,第一時間對此產生了濃厚的興趣,第一時間查閲了官方文檔,尋找實現方案,並以官方Api為基礎,設計了DragAndDropKit,採用Swift編寫,自帶Drop、Drag命名空間,支持鏈式語法,原則上兩行代碼就可以讓您項目支持拖拽資源分享到其他應用。

支持版本

原則上支持iPad OS 11 + , iPhone 是 iOS15+才支持。

參考文檔

drag and drop

下載地址

cocoaPods:

```

pod 'DragAndDropKit', '0.1.0'

```

github:

https://github.com/JerryFans/DragAndDropKit

DragAndDropKit演示與用法

Drag

拖拽本應用的data到其他實現了Drop協議的應用(親測支持系統相冊、備忘錄、網頁裏面的文本選中範圍後直接拖拽等) DragAndDropKit本組件目前支持拖拽UIImage、本地視頻(路徑下的視頻)、網絡圖片、網絡視頻、文本等。目前支持UIView及其類UIImageView、UILabel等、以及TableView、CollectionView快速拖動其子Cell。

UIView Drag Usage

最快只需兩行代碼即可實現拖拽,支持鏈式寫法

```

/*

你想拖拽時候給予的souce, 目前支持NetworkImageDropSource、NetworkVideoDropSource、ImageDropSource、VideoDropSource、TextDropSource五種

*/

self.networkImageView.drag.dropSource = NetworkImageDropSource(imageUrl: "http://image.jerryfans.com/sample.jpg")

//開啟拖拽

self.networkImageView.drag.enabled()

```

以及可選協議轉鏈式閉包

```

self.networkImageView.drag.enabled().didEndSession { interaction, session, operation in

}.didMoveSession { interaction, session in

}.didPreviewForDragSession { interaction, item, session in

return

}.didAllowsMoveOperationSession { interaction, session in

return false

}

```

UICollectionView & UITableView Drag Usage

UICollectionView、UITableView因為實習的協議不同,但本質寫法是差不多的。

兩者enabled後都必須至少實現tableViewDidItemsForBeginning 或 collectionViewDidItemsForBeginning 閉包,返回相應的DragItem。DragItem封裝的也是上面所説的5種DropSource。

tableView

```

tableView.drag.enabled().tableViewDidItemsForBeginning { [weak self] tableView, session, indexPath in

guard let self = self else { return [] }

//if you are the custom model, you should convert to DropSource Object (Text,Image or Video Drop Source)

let source = self.models[indexPath.row]

let itemProvider = NSItemProvider(object: source)

return [

UIDragItem(itemProvider: itemProvider)

]

}

```

collectionView,如果要實現一些生命週期方法,可以實現一下生命週期閉包,同樣是鏈式語法。

```

collectionView.drag.enabled()

.collectionViewDidItemsForBeginning { [weak self] collectionView, session, indexPath in

return self?.dragAndDropVM.dragItems(for: indexPath) ?? []

}.collectionViewWillBeginDragSession { collectionView, session in

JFPopup.toast(hit: "collection view will begin drag")

}.collectionViewDidEndDragSession { collectionView, session in

JFPopup.toast(hit: "collection view did end drag")

}

```

|

Drop

從其他應用的接收data到到本應用(親測支持系統相冊、備忘錄、QQ發送聊天等) DragAndDropKit本組件目前支持Drop 接收 UIImage、本地視頻(路徑下的視頻)、網絡圖片、網絡視頻、文本等。目前也是支持UIView及其類UIImageView、UILabel等、以及TableView、CollectionView快速拖動其子Cell。

Usage

支持類型參數,所有UIView類別、TableView、CollectionView、均可賦值supportSources,用來聲明drop接收時候能支持的類型數據,默認全部支持(Image、Video、Text)三種。(注:並不是系統api只支持這三種,是這三種比較廣泛,第一期先支持此三種數據的接收)

```

c.drop.supportSources = [.rawImage,.rawVideo,.text]

```

UIView Drop, didReceivedDropSource閉包必須實現用以接收到source後你對source的處理,其他可選。

```

self.view.drop.supportSources = [.rawImage]

self.view.drop.enabled().didReceivedDropSource { [weak self] dropSources in

for (_, item) in dropSources.enumerated() {

if let imageSource = item as? ImageDropSource {

self?.imageView.image = imageSource.image

self?.imageView.layer.borderWidth = 0.0

break

}

}

}.didEnterDropSession { interaction, session in

if session.localDragSession == nil {

JFPopupView.popup.toast {

[.hit("請移入右上角圖片中替換"),

.withoutAnimation(true),

.position(.top),

.autoDismissDuration(.seconds(value: 3)),

.bgColor(UIColor.jf.rgb(0x000000, alpha: 0.3))

]

}

}

}.didUpdateDropSource { [weak self] interaction, session in

guard let self = self else {

return UIDropProposal(operation: UIDropOperation.cancel)

}

let dropLocation = session.location(in: self.view)

let operation: UIDropOperation

if self.imageView.frame.contains(dropLocation) {

operation = session.localDragSession == nil ? .copy : .move

self.checkIsMatch(match: true)

} else {

operation = .cancel

self.checkIsMatch(match: false)

}

self.updateLayers(forDropLocation: dropLocation)

return UIDropProposal(operation: operation)

}.didEndDropSession { [weak self] interaction, session in

guard let self = self else { return }

let dropLocation = session.location(in: self.view)

self.updateLayers(forDropLocation: dropLocation)

self.checkIsMatch(match: false)

}.didExitDropSession { [weak self] interaction, session in

guard let self = self else { return }

self.imageView.layer.borderWidth = 0.0

}

}

```

UICollectionView類似,也是collectionViewDidReceivedDropSource必須處理,其他生命週期閉包,可選。

```

c.drop.supportSources = [.rawImage,.rawVideo,.text]

c.drop.enabled().collectionViewDidReceivedDropSource { [weak self] collectionView, coordinator, dropSources in

let destinationIndexPath: IndexPath

if let indexPath = coordinator.destinationIndexPath {

destinationIndexPath = indexPath

} else {

let item = collectionView.numberOfItems(inSection: 0)

destinationIndexPath = IndexPath(item: item, section: 0)

}

var indexPaths = IndexPath

for (index, item) in dropSources.enumerated() {

let indexPath = IndexPath(item: destinationIndexPath.item + index, section: destinationIndexPath.section)

self?.dragAndDropVM.addItem(item, at: indexPath.item)

indexPaths.append(indexPath)

}

self?.collectionView.insertItems(at: indexPaths)

}

```

UITableView類似,也是tableViewDidReceivedDropSource必須處理,其他生命週期閉包,可選。

```

t.drop.supportSources = [.rawImage,.rawVideo,.text]

t.drop.enabled().tableViewDidReceivedDropSource { [weak self] tableView, coordinator, dropSources in

guard let self = self else { return }

let destinationIndexPath: IndexPath

if let indexPath = coordinator.destinationIndexPath {

destinationIndexPath = indexPath

} else {

let item = tableView.numberOfRows(inSection: 0)

destinationIndexPath = IndexPath(row: item, section: 0)

}

var indexPaths = IndexPath

for (index, item) in dropSources.enumerated() {

let indexPath = IndexPath(row: destinationIndexPath.item + index, section: destinationIndexPath.section)

self.models.insert(item, at: indexPath.row)

indexPaths.append(indexPath)

}

tableView.insertRows(at: indexPaths, with: .bottom)

}

```

效果:

後續支持

  • tableView & collectionView 和系統相冊一樣支持多選拖拽支持(目前只能一個個拖cell)

  • 更多DropSource的支持