我有一个 collectionview 并将支持 iOS 11 的拖放功能。一个要求是需要通过将单元格拖到视图底部的垃圾箱上来删除它们。是否还有另一种可能性,然后使用第二个包含删除符号的集合视图?
不幸的是,UIView 不能是 UICollectionViewDropDelegate。
我有一个 collectionview 并将支持 iOS 11 的拖放功能。一个要求是需要通过将单元格拖到视图底部的垃圾箱上来删除它们。是否还有另一种可能性,然后使用第二个包含删除符号的集合视图?
不幸的是,UIView 不能是 UICollectionViewDropDelegate。
到目前为止最好的解决方案是在删除图标上方放置一个不可见的集合视图。这是我的代码:
import UIKit
class DragDropViewController: UIViewController
{
private var items1 = [String]()
//MARK: Outlets
@IBOutlet weak var collectionView1: UICollectionView!
@IBOutlet weak var collectionView2: UICollectionView!
@IBOutlet weak var trashImage: UIImageView!
private func createData(){
for index in 1...130{
items1.append("\(index)")
}
}
private func indexForIdentifier(identifier: String)->Int?{
return items1.firstIndex(of: identifier)
}
//MARK: View Lifecycle Methods
override func viewDidLoad()
{
super.viewDidLoad()
createData()
trashImage.alpha = 0
trashImage.layer.cornerRadius = 30
self.collectionView1.dragInteractionEnabled = true
self.collectionView1.dragDelegate = self
self.collectionView1.dropDelegate = self
self.collectionView2.dropDelegate = self
}
//MARK: Private Methods
/// This method moves a cell from source indexPath to destination indexPath within the same collection view. It works for only 1 item. If multiple items selected, no reordering happens.
///
/// - Parameters:
/// - coordinator: coordinator obtained from performDropWith: UICollectionViewDropDelegate method
/// - destinationIndexPath: indexpath of the collection view where the user drops the element
/// - collectionView: collectionView in which reordering needs to be done.
private func reorderItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView)
{
let items = coordinator.items
if items.count == 1, let item = items.first, let sourceIndexPath = item.sourceIndexPath
{
var dIndexPath = destinationIndexPath
if dIndexPath.row >= collectionView.numberOfItems(inSection: 0)
{
dIndexPath.row = collectionView.numberOfItems(inSection: 0) - 1
}
collectionView.performBatchUpdates({
self.items1.remove(at: sourceIndexPath.row)
self.items1.insert(item.dragItem.localObject as! String, at: dIndexPath.row)
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [dIndexPath])
})
coordinator.drop(items.first!.dragItem, toItemAt: dIndexPath)
}
}
/// This method copies a cell from source indexPath in 1st collection view to destination indexPath in 2nd collection view. It works for multiple items.
///
/// - Parameters:
/// - coordinator: coordinator obtained from performDropWith: UICollectionViewDropDelegate method
/// - destinationIndexPath: indexpath of the collection view where the user drops the element
/// - collectionView: collectionView in which reordering needs to be done.
private func removeItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView)
{
collectionView.performBatchUpdates({
for item in coordinator.items
{
guard let identifier = item.dragItem.localObject as? String else {
return
}
if let index = indexForIdentifier(identifier: identifier){
let indexPath = IndexPath(row: index, section: 0)
items1.remove(at: index)
collectionView1.deleteItems(at: [indexPath])
}
}
})
}
}
// MARK: - UICollectionViewDataSource Methods
extension DragDropViewController : UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return collectionView == self.collectionView1 ? self.items1.count : 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath) as! DragDropCollectionViewCell
cell.customLabel.text = self.items1[indexPath.row].capitalized
return cell
}
}
// MARK: - UICollectionViewDragDelegate Methods
extension DragDropViewController : UICollectionViewDragDelegate
{
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem]
{
let item = self.items1[indexPath.row]
let itemProvider = NSItemProvider(object: item as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
func collectionView(_ collectionView: UICollectionView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem]
{
let item = self.items1[indexPath.row]
let itemProvider = NSItemProvider(object: item as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
}
// MARK: - UICollectionViewDropDelegate Methods
extension DragDropViewController : UICollectionViewDropDelegate
{
func collectionView(_ collectionView: UICollectionView, canHandle session: UIDropSession) -> Bool
{
return session.canLoadObjects(ofClass: NSString.self)
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal
{
if collectionView === self.collectionView1
{
return collectionView.hasActiveDrag ?
UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) :
UICollectionViewDropProposal(operation: .forbidden)
}
else
{
if collectionView.hasActiveDrag{
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
for item in session.items
{
guard let identifier = item.localObject as? String else {
return UICollectionViewDropProposal(operation: .forbidden)
}
//not every cell is allowed to be deleted
if Int(identifier)! % 3 == 0{
return UICollectionViewDropProposal(operation: .forbidden)
}
}
trashImage.backgroundColor = UIColor.red.withAlphaComponent(0.4)
return UICollectionViewDropProposal(operation: .move, intent: .unspecified)
}
}
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator)
{
let destinationIndexPath: IndexPath
if let indexPath = coordinator.destinationIndexPath
{
destinationIndexPath = indexPath
}
else
{
// Get last index path of table view.
let section = collectionView.numberOfSections - 1
let row = collectionView.numberOfItems(inSection: section)
destinationIndexPath = IndexPath(row: row, section: section)
}
if coordinator.proposal.operation == .move{
if coordinator.proposal.intent == .insertAtDestinationIndexPath{
self.reorderItems(coordinator: coordinator, destinationIndexPath:destinationIndexPath, collectionView: collectionView)
}
else{
self.removeItems(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
}
}
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidExit session: UIDropSession) {
trashImage.backgroundColor = UIColor.clear
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidEnd session: UIDropSession) {
trashImage.backgroundColor = UIColor.clear
}
}