前言
前段時間蘋果剛推出了iOS15正式版曼玩,我也是第一時間就升級了體驗。期間體驗到了一個非常有趣的交互如下視頻禽绪。
[圖片上傳失敗...(image-6e15f5-1641800973359)]
如視頻所示妖胀,iOS15下的蘋果系統(tǒng)相冊支持將圖片、視頻猴贰,文本等直接拖拽復(fù)制到其他應(yīng)用(目前親測自帶備忘錄、騰訊QQ等是支持的)。作為一個iOS工程師上煤,第一時間對此產(chǎn)生了濃厚的興趣,第一時間查閱了官方文檔著淆,尋找實現(xiàn)方案劫狠,并以官方Api為基礎(chǔ),設(shè)計了DragAndDropKit,采用Swift編寫永部,自帶Drop独泞、Drag命名空間,支持鏈?zhǔn)秸Z法苔埋,原則上兩行代碼就可以讓您項目支持拖拽資源分享到其他應(yīng)用懦砂。
支持版本
原則上支持iPad OS 11 + , iPhone 是 iOS15+才支持。
參考文檔
下載地址
cocoaPods:
pod 'DragAndDropKit', '0.1.0'
github:
https://github.com/JerryFans/DragAndDropKit
DragAndDropKit演示與用法
[圖片上傳失敗...(image-49125d-1641800973359)]
Drag
拖拽本應(yīng)用的data到其他實現(xiàn)了Drop協(xié)議的應(yīng)用(親測支持系統(tǒng)相冊组橄、備忘錄孕惜、網(wǎng)頁里面的文本選中范圍后直接拖拽等) DragAndDropKit本組件目前支持拖拽UIImage、本地視頻(路徑下的視頻)晨炕、網(wǎng)絡(luò)圖片衫画、網(wǎng)絡(luò)視頻、文本等瓮栗。目前支持UIView及其類UIImageView削罩、UILabel等、以及TableView费奸、CollectionView快速拖動其子Cell弥激。
UIView Drag Usage
最快只需兩行代碼即可實現(xiàn)拖拽,支持鏈?zhǔn)綄懛?/p>
/*
你想拖拽時候給予的souce, 目前支持NetworkImageDropSource、NetworkVideoDropSource愿阐、ImageDropSource微服、VideoDropSource、TextDropSource五種
*/
self.networkImageView.drag.dropSource = NetworkImageDropSource(imageUrl: "http://image.jerryfans.com/sample.jpg")
//開啟拖拽
self.networkImageView.drag.enabled()
以及可選協(xié)議轉(zhuǎn)鏈?zhǔn)介]包
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因為實習(xí)的協(xié)議不同以蕴,但本質(zhì)寫法是差不多的糙麦。
兩者enabled后都必須至少實現(xiàn)tableViewDidItemsForBeginning 或 collectionViewDidItemsForBeginning 閉包,返回相應(yīng)的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,如果要實現(xiàn)一些生命周期方法,可以實現(xiàn)一下生命周期閉包宝与,同樣是鏈?zhǔn)秸Z法焚廊。
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")
}
[圖片上傳失敗...(image-cae300-1641800973359)] | Drop
從其他應(yīng)用的接收data到到本應(yīng)用(親測支持系統(tǒng)相冊、備忘錄习劫、QQ發(fā)送聊天等) DragAndDropKit本組件目前支持Drop 接收 UIImage咆瘟、本地視頻(路徑下的視頻)、網(wǎng)絡(luò)圖片诽里、網(wǎng)絡(luò)視頻袒餐、文本等。目前也是支持UIView及其類UIImageView须肆、UILabel等匿乃、以及TableView桩皿、CollectionView快速拖動其子Cell豌汇。
Usage
支持類型參數(shù),所有UIView類別泄隔、TableView拒贱、CollectionView、均可賦值supportSources佛嬉,用來聲明drop接收時候能支持的類型數(shù)據(jù)逻澳,默認(rèn)全部支持(Image、Video暖呕、Text)三種斜做。(注:并不是系統(tǒng)api只支持這三種,是這三種比較廣泛湾揽,第一期先支持此三種數(shù)據(jù)的接收)
c.drop.supportSources = [.rawImage,.rawVideo,.text]
UIView Drop, didReceivedDropSource閉包必須實現(xiàn)用以接收到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)
}
效果:
[圖片上傳失敗...(image-84abfd-1641800973359)]
后續(xù)支持
- tableView & collectionView 和系統(tǒng)相冊一樣支持多選拖拽支持(目前只能一個個拖cell)
- 更多DropSource的支持