我想用 来实现拖放功能UICollectionViewDragDelegate
,UICollectionViewDropDelegate
它工作得很好,但我需要收缩下面的单元格,同时用拖动行为提升一个单元格,并在用户将单元格放回单元格时收缩回原始大小。但不知何故,我无法使用下面的代码获得稳定的结果。动画很奇怪,并且在尝试拖动屏幕边缘的单元格时行为不可预测。我怎样才能使结果更可预测?
import UIKit
class ViewController: UIViewController {
@IBOutlet var collectionView: UICollectionView! {
didSet {
collectionView.delegate = self
collectionView.dataSource = self
collectionView.dragDelegate = self
collectionView.dropDelegate = self
collectionView.dragInteractionEnabled = true
}
}
var items: [UIColor] = [.green, .blue, .brown, .cyan, .red, .magenta, .yellow, .systemPink]
var isShrink: Bool = false {
didSet {
//collectionView.collectionViewLayout.invalidateLayout()
collectionView.performBatchUpdates({}, completion: { _ in })
}
}
}
extension ViewController: UIGestureRecognizerDelegate {}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout _: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
isShrink ? CGSize(width: 60, height: 60) : CGSize(width: 80, height: 60)
}
}
class Cell: UICollectionViewCell {
var shrink: ((Bool) -> Void)?
required init?(coder: NSCoder) {
super.init(coder: coder)
let gesture = UILongPressGestureRecognizer(target: self, action: #selector(longPressed(gesture:)))
addGestureRecognizer(gesture)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//shrink?(true)
print("touchesBegan")
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touchesEnd")
}
override init(frame: CGRect) {
super.init(frame: frame)
}
@objc func longPressed(gesture: UILongPressGestureRecognizer) {
switch gesture.state {
case .began:
print("began")
case .ended:
print("ended")
default:
print("default")
}
}
// weak var coordinator: DragCoordinator?
//
override func dragStateDidChange(_ dragState: UICollectionViewCell.DragState) {
super.dragStateDidChange(dragState)
switch dragState {
case .dragging:
shrink?(true)
case .lifting:
shrink?(true)
case .none:
shrink?(false)
@unknown default:
fatalError()
}
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int {
items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! Cell
cell.shrink = { [weak self] isShrink in
self?.isShrink = isShrink
}
cell.backgroundColor = items[indexPath.row]
return cell
}
}
extension ViewController: UICollectionViewDragDelegate {
func collectionView(_ cv: UICollectionView,
itemsForBeginning _: UIDragSession,
at indexPath: IndexPath) -> [UIDragItem] {
[.init(itemProvider: .init(object: "\(indexPath.row)" as NSString))]
}
}
extension ViewController: UICollectionViewDropDelegate {
func collectionView(_ collectionView: UICollectionView,
performDropWith coordinator: UICollectionViewDropCoordinator) {
guard let destinationIndexPath = coordinator.destinationIndexPath else {
return
}
let item = coordinator.items[0]
switch coordinator.proposal.operation {
case .move:
if let sourceIndexPath = item.sourceIndexPath {
collectionView.performBatchUpdates({
let item = items[sourceIndexPath.row]
items.remove(at: sourceIndexPath.row)
items.insert(item, at: destinationIndexPath.row)
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIndexPath])
})
}
coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
default:
return
}
}
func collectionView(_: UICollectionView,
dropSessionDidUpdate session: UIDropSession,
withDestinationIndexPath _: IndexPath?) -> UICollectionViewDropProposal {
guard session.localDragSession != nil else {
return .init(operation: .copy, intent: .insertAtDestinationIndexPath)
}
guard session.items.count == 1 else {
return .init(operation: .cancel)
}
return .init(operation: .move, intent: .insertAtDestinationIndexPath)
}
}