拖放 - 从我的模型创建一个 NSItemProvider
Drag and Drop - create an NSItemProvider from my Model
让我们分部分来!
我正在尝试在我的 UICollectionViewController
中实现 Drag and Drop
。
UICollectionView
的数据源是我创建的自定义 Model Struct
的 array
。
根据需要,我设置了 collectionView.dragDelegate = self
并通过这样做实现了 required protocol function
itemsForBeginning session: UIDragSession...
这是我的问题开始的地方:
struct Model {
// some variables
// Some initializations
}
var myModelDatasource: [Model] = [model1, model2, model3, ...] // it's a simple case example
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let item = myModelDatasource[indexPath.row]
let itemProvider = NSItemProvider(object: item)
let dragItem = UIDragItem(itemProvider: itemProvider) // <-- ERROR HERE, Even If i force cast as NSItemProviderWriting
dragItem.localObject = item
return [dragItem]
}
我无法创建 dragItem
,因为我的模型不符合类型 NSItemProviderWriting
。
如果我强制数据源为 String
类型并将项目转换为 NSString
它可以工作,但不适用于我的 struct Model
.
有谁知道如何解决这个问题?
您应该为您的 Model
使用 class
(不是结构),因为正如您所建议的,您必须符合 NSItemProviderWriting
(继承自 NSObjectProtocol
):
The protocol you implement on a class to allow an item provider to retrieve data from an instance of the class.
许多 API 需要 NSObject
的子 class,因此您必须使用 class,
Apple blog: struct vs class
所以你的 Model
应该是这样的:
class Model : NSObject, NSItemProviderWriting {
public static var writableTypeIdentifiersForItemProvider: [String] {
return [] // something here
}
public func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Swift.Void) -> Progress? {
return nil // something here
}
}
这是我实现的完整示例
1-型号class/struct
2-调用viewDidload中的setup方法
3- 实施拖放 collectionview 协议
class ImageRequestModel {
var uuid = UUID().uuidString
var filename: String?
var url: String? // displayable
var caption:String?
var image: UIImage? // its mean new or modifiable
}
func setupCollectionView(){
self.collectionView?.registerCell(id: PhotoCVC.className)
self.collectionView?.collectionViewLayout = UICollectionViewLayout.createTwoColumnLayout()
self.collectionView?.dataSource = self
self.collectionView?.delegate = self
self.collectionView?.dragInteractionEnabled = true
self.collectionView?.dragDelegate = self
self.collectionView?.dropDelegate = self
self.setupRefreshControl()
}
extension InspectionPhotosView: UICollectionViewDropDelegate {
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
var destinationIndexPath: IndexPath
if let indexpath = coordinator.destinationIndexPath {
destinationIndexPath = indexpath
} else {
guard let row = self.collectionView?.numberOfItems(inSection: 0) else { return }
destinationIndexPath = IndexPath(item: row - 1, section: 0)
}
if coordinator.proposal.operation == .move {
Logger.debug(message: "\(destinationIndexPath.row)")
self.reorderItems(coordinater: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
}
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
// if session.localDragSession != nil {
// return UICollectionViewDropProposal(operation: .forbidden)
// } else {
// return UICollectionViewDropProposal(
// operation: .copy,
// intent: .insertAtDestinationIndexPath)
// }
if collectionView.hasActiveDrag {
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
return UICollectionViewDropProposal(operation: .forbidden)
}
fileprivate func reorderItems(coordinater: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) {
if let item = coordinater.items.first, let sourceIndexPath = item.sourceIndexPath {
collectionView.performBatchUpdates ({
let object = imageList.remove(at: sourceIndexPath.item)
// object.order = destinationIndexPath.row
self.imageList.insert(object, at: destinationIndexPath.item)
self.updateCollectionView(imageList)
self.addPhotoView?.isImageSelected = true
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIndexPath])
}, completion: nil)
}
}
}
extension InspectionPhotosView: UICollectionViewDragDelegate {
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let item = self.imageList[indexPath.row]
let itemProvider = NSItemProvider(object: item.uuid as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
return [dragItem]
}
}
让我们分部分来!
我正在尝试在我的 UICollectionViewController
中实现 Drag and Drop
。
UICollectionView
的数据源是我创建的自定义 Model Struct
的 array
。
根据需要,我设置了 collectionView.dragDelegate = self
并通过这样做实现了 required protocol function
itemsForBeginning session: UIDragSession...
这是我的问题开始的地方:
struct Model {
// some variables
// Some initializations
}
var myModelDatasource: [Model] = [model1, model2, model3, ...] // it's a simple case example
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let item = myModelDatasource[indexPath.row]
let itemProvider = NSItemProvider(object: item)
let dragItem = UIDragItem(itemProvider: itemProvider) // <-- ERROR HERE, Even If i force cast as NSItemProviderWriting
dragItem.localObject = item
return [dragItem]
}
我无法创建 dragItem
,因为我的模型不符合类型 NSItemProviderWriting
。
如果我强制数据源为 String
类型并将项目转换为 NSString
它可以工作,但不适用于我的 struct Model
.
有谁知道如何解决这个问题?
您应该为您的 Model
使用 class
(不是结构),因为正如您所建议的,您必须符合 NSItemProviderWriting
(继承自 NSObjectProtocol
):
The protocol you implement on a class to allow an item provider to retrieve data from an instance of the class.
许多 API 需要 NSObject
的子 class,因此您必须使用 class,
Apple blog: struct vs class
所以你的 Model
应该是这样的:
class Model : NSObject, NSItemProviderWriting {
public static var writableTypeIdentifiersForItemProvider: [String] {
return [] // something here
}
public func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Swift.Void) -> Progress? {
return nil // something here
}
}
这是我实现的完整示例
1-型号class/struct
2-调用viewDidload中的setup方法
3- 实施拖放 collectionview 协议
class ImageRequestModel {
var uuid = UUID().uuidString
var filename: String?
var url: String? // displayable
var caption:String?
var image: UIImage? // its mean new or modifiable
}
func setupCollectionView(){
self.collectionView?.registerCell(id: PhotoCVC.className)
self.collectionView?.collectionViewLayout = UICollectionViewLayout.createTwoColumnLayout()
self.collectionView?.dataSource = self
self.collectionView?.delegate = self
self.collectionView?.dragInteractionEnabled = true
self.collectionView?.dragDelegate = self
self.collectionView?.dropDelegate = self
self.setupRefreshControl()
}
extension InspectionPhotosView: UICollectionViewDropDelegate {
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
var destinationIndexPath: IndexPath
if let indexpath = coordinator.destinationIndexPath {
destinationIndexPath = indexpath
} else {
guard let row = self.collectionView?.numberOfItems(inSection: 0) else { return }
destinationIndexPath = IndexPath(item: row - 1, section: 0)
}
if coordinator.proposal.operation == .move {
Logger.debug(message: "\(destinationIndexPath.row)")
self.reorderItems(coordinater: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
}
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
// if session.localDragSession != nil {
// return UICollectionViewDropProposal(operation: .forbidden)
// } else {
// return UICollectionViewDropProposal(
// operation: .copy,
// intent: .insertAtDestinationIndexPath)
// }
if collectionView.hasActiveDrag {
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
return UICollectionViewDropProposal(operation: .forbidden)
}
fileprivate func reorderItems(coordinater: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) {
if let item = coordinater.items.first, let sourceIndexPath = item.sourceIndexPath {
collectionView.performBatchUpdates ({
let object = imageList.remove(at: sourceIndexPath.item)
// object.order = destinationIndexPath.row
self.imageList.insert(object, at: destinationIndexPath.item)
self.updateCollectionView(imageList)
self.addPhotoView?.isImageSelected = true
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIndexPath])
}, completion: nil)
}
}
}
extension InspectionPhotosView: UICollectionViewDragDelegate {
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let item = self.imageList[indexPath.row]
let itemProvider = NSItemProvider(object: item.uuid as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
return [dragItem]
}
}