#swift #uicollectionview #drag-and-drop
#swift #uicollectionview #перетаскивание
Вопрос:
У меня есть CollectionView, где все мои ячейки выровнены по центру представления, используя пользовательский макет потока. Вот код для collectionViewController:
let columnLayout = FlowLayout(
minimumInteritemSpacing: 10,
minimumLineSpacing: 10,
sectionInset: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
)
var dataSource: [String] = ["USA", "Brazil", "China","Really long long long", "Unite Kingdom", "Japan", "Mexico", "India", "Really long long", "Short", "USA", "Brazil", "China","Really long long long", "Unite Kingdom", "Japan", "Mexico", "India", "Really long long"]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.collectionViewLayout = columnLayout
collectionView.contentInsetAdjustmentBehavior = .always
collectionView.register(TestCell.self, forCellWithReuseIdentifier: "Cell")
collectionView.dragInteractionEnabled = true
collectionView.dragDelegate = self
collectionView.dropDelegate = self
collectionView.delegate = self
collectionView.dataSource = self
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataSource.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// dataArary is the managing array for your UICollectionView.
let item: String = dataSource[indexPath.row]
return CGSize(width: item.widthOfString(usingFont: .systemFont(ofSize: 16)) 25, height: 40)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? TestCell
cell?.textLabel.text = dataSource[indexPath.row]
return cell!
}
fileprivate func reorderItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) {
if let item = coordinator.items.first,
let sourceIndexPath = item.sourceIndexPath {
collectionView.performBatchUpdates ({
self.dataSource.remove(at: sourceIndexPath.item)
self.dataSource.insert(item.dragItem.localObject as! String, at: destinationIndexPath.item)
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIndexPath])
}, completion: nil)
collectionView.reloadData()
coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
}
Код для класса FlowLayout:
class FlowLayout: UICollectionViewFlowLayout {
required init(minimumInteritemSpacing: CGFloat = 0, minimumLineSpacing: CGFloat = 0, sectionInset: UIEdgeInsets = .zero) {
super.init()
estimatedItemSize = UICollectionViewFlowLayout.automaticSize
self.minimumInteritemSpacing = minimumInteritemSpacing
self.minimumLineSpacing = minimumLineSpacing
self.sectionInset = sectionInset
sectionInsetReference = .fromSafeArea
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let layoutAttributes = super.layoutAttributesForElements(in: rect)!.map { $0.copy() as! UICollectionViewLayoutAttributes }
guard scrollDirection == .vertical else { return layoutAttributes }
// Filter attributes to compute only cell attributes
let cellAttributes = layoutAttributes.filter({ $0.representedElementCategory == .cell })
// Group cell attributes by row (cells with same vertical center) and loop on those groups
for (_, attributes) in Dictionary(grouping: cellAttributes, by: { ($0.center.y / 10).rounded(.up) * 10 }) {
// Get the total width of the cells on the same row
let cellsTotalWidth = attributes.reduce(CGFloat(0)) { (partialWidth, attribute) -> CGFloat in
partialWidth attribute.size.width
}
// Calculate the initial left inset
let totalInset = collectionView!.safeAreaLayoutGuide.layoutFrame.width - cellsTotalWidth - sectionInset.left - sectionInset.right - minimumInteritemSpacing * CGFloat(attributes.count - 1)
var leftInset = (totalInset / 2 * 10).rounded(.down) / 10 sectionInset.left
// Loop on cells to adjust each cell's origin and prepare leftInset for the next cell
for attribute in attributes {
attribute.frame.origin.x = leftInset
leftInset = attribute.frame.maxX minimumInteritemSpacing
}
}
return layoutAttributes
}
}
Затем я добавил расширения UICollectionViewDragDelegate и UICollectionViewDropDelegate, чтобы позволить пользователю изменять порядок ячеек. Два расширения:
extension CollectionViewController: UICollectionViewDragDelegate {
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let item = self.dataSource[indexPath.row]
let itemProvider = NSItemProvider(object: item as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
}
extension CollectionViewController: UICollectionViewDropDelegate {
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
if collectionView.hasActiveDrag {
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
return UICollectionViewDropProposal(operation: .forbidden)
}
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
var destinationindexPath: IndexPath
if let indexPath = coordinator.destinationIndexPath {
destinationindexPath = indexPath
} else {
let row = collectionView.numberOfItems(inSection: 0)
destinationindexPath = IndexPath(item: row - 1, section: 0)
}
if coordinator.proposal.operation == .move {
self.reorderItems(coordinator: coordinator, destinationIndexPath: destinationindexPath, collectionView: collectionView)
}
}
}
По какой-то странной причине ячейки отключаются в приложении при их изменении порядка:
Спасибо за помощь
Комментарии:
1. вы нашли решение своей проблемы?