0 xcode uicollectionviewcell swift uicollectionviewflowlayout
您好,我想使用 uicollectionview 进行拖放。当执行拖放时,它正在移动内容,我想像照片中那样进行操作。我想让盒子自己搬。例如; 当我将照片拖动到 4 时,我应该保留带有完整测量值的红色区域。将照片 6 交换到照片 1,就像将照片 3 移到左侧一样。我在 uicollectionview 中研究了很多,但我无法\xe2\x80\x99 找到类似的东西。请帮我
\n\nimport UIKit\n\nfinal class ViewController: UIViewController {\n\n@IBOutlet weak var collectionView: UICollectionView!\n\n var cellIds = ["image 1","image 2","image 3","image 4","image 5","6","7"]\n override func viewDidLoad() {\n super.viewDidLoad()\n\n let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout\n flowLayout.estimatedItemSize = CGSize(width: 200, height: 10)\n\n let gestureRecognizer = UILongPressGestureRecognizer(target: self,\n action: #selector(self.handleLongPress(gestureRecognizer:)))\n collectionView.addGestureRecognizer(gestureRecognizer)\n}\n\n@objc func handleLongPress(gestureRecognizer: UILongPressGestureRecognizer) {\n\n guard let view = gestureRecognizer.view else { return }\n let location = gestureRecognizer.location(in: view)\n\n switch gestureRecognizer.state {\n case .began:\n guard let selectedIndexPath = collectionView.indexPathForItem(at: location) else { break }\n collectionView.beginInteractiveMovementForItem(at: selectedIndexPath)\n case .changed:\n collectionView.updateInteractiveMovementTargetPosition(location)\n case .ended:\n collectionView.endInteractiveMovement()\n default:\n collectionView.cancelInteractiveMovement()\n }\n }\n }\n\n\n\nextension ViewController: UICollectionViewDataSource,\n UICollectionViewDelegateFlowLayout\n{\n\n\nfunc numberOfSections(in collectionView: UICollectionView) -> Int {\n return 1\n}\nfunc collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {\n return cellIds.count\n}\n\nfunc collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {\n\n let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SampleCell", for: indexPath) as! SampleCell\n\n let text = cellIds[indexPath.item]\n cell.label.text = text\n\n return cell\n}\n\nfunc collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {\n return true\n}\n\nfunc collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {\n let text = cellIds.remove(at: sourceIndexPath.item)\n cellIds.insert(text, at: destinationIndexPath.item)\n\n collectionView.reloadData()\n}\n\nfunc collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {\n if (indexPath.row==0)\n {\n return CGSize(width: 190, height: 100)\n }\n\n if (indexPath.row==1)\n {\n return CGSize(width: 190, height: 100)\n }\n\n if (indexPath.row==2)\n {\n return CGSize(width: 190, height: 400)\n }\n\n if (indexPath.row==3)\n {\n return CGSize(width: 400, height: 200)\n }\n return CGSize(width: 0, height: 0)\n}\n\n\n}\n\nfinal class SampleCell: UICollectionViewCell {\n@IBOutlet weak var label: UILabel!\n\noverride func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {\n setNeedsLayout()\n layoutIfNeeded()\n\n\n\n let size = self.systemLayoutSizeFitting(layoutAttributes.size)\n\n var newFrame = layoutAttributes.frame\n // note: don\'t change the width\n newFrame.size.height = ceil(size.height)\n\n layoutAttributes.frame = newFrame\n\n return layoutAttributes\n}\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n
您可以使用UICollectionViewDragDelegate,
对于多个部分,为了拖动到最终项目,我们应该在拖动时添加一个额外的项目。

示例代码:
视图控制器:
import UIKit
enum CellModel {
case simple(text: String)
case availableToDropAtEnd
}
class SecondController: UIViewController {
private lazy var cellIdentifier = "cellIdentifier"
private lazy var supplementaryViewIdentifier = "supplementaryViewIdentifier"
private lazy var sections = 10
private lazy var itemsInSection = 2
private lazy var numberOfElementsInRow = 3
private lazy var data: [[CellModel]] = {
var count = 0
return (0 ..< sections).map { _ in
return (0 ..< itemsInSection).map { _ -> CellModel in
count += 1
return .simple(text: "cell \(count)")
}
}
}()
override func viewDidLoad() {
super.viewDidLoad()
let collectionViewFlowLayout = UICollectionViewFlowLayout()
collectionViewFlowLayout.minimumLineSpacing = 5
collectionViewFlowLayout.minimumInteritemSpacing = 5
let _numberOfElementsInRow = CGFloat(numberOfElementsInRow)
let allWidthBetwenCells = _numberOfElementsInRow == 0 ? 0 : collectionViewFlowLayout.minimumInteritemSpacing*(_numberOfElementsInRow-1)
let width = (view.frame.width - allWidthBetwenCells)/_numberOfElementsInRow
collectionViewFlowLayout.itemSize = CGSize(width: width, height: width)
collectionViewFlowLayout.headerReferenceSize = CGSize(width: 0, height: 40)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout)
collectionView.backgroundColor = .white
view.addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
collectionView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
collectionView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: cellIdentifier)
collectionView.register(SupplementaryView.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: supplementaryViewIdentifier)
collectionView.dragInteractionEnabled = true
collectionView.reorderingCadence = .fast
collectionView.dropDelegate = self
collectionView.dragDelegate = self
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension SecondController: UICollectionViewDelegate { }
extension SecondController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return data.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data[section].count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! CollectionViewCell
switch data[indexPath.section][indexPath.item] {
case .simple(let text):
cell.label?.text = text
cell.backgroundColor = .gray
case .availableToDropAtEnd:
cell.backgroundColor = UIColor.green.withAlphaComponent(0.3)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
return collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: supplementaryViewIdentifier, for: indexPath)
}
}
extension SecondController: UICollectionViewDragDelegate {
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let itemProvider = NSItemProvider(object: "\(indexPath)" as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = data[indexPath.section][indexPath.row]
return [dragItem]
}
func collectionView(_ collectionView: UICollectionView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem] {
let itemProvider = NSItemProvider(object: "\(indexPath)" as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = data[indexPath.section][indexPath.row]
return [dragItem]
}
func collectionView(_ collectionView: UICollectionView, dragSessionWillBegin session: UIDragSession) {
var itemsToInsert = [IndexPath]()
(0 ..< data.count).forEach {
itemsToInsert.append(IndexPath(item: data[$0].count, section: $0))
data[$0].append(.availableToDropAtEnd)
}
collectionView.insertItems(at: itemsToInsert)
}
func collectionView(_ collectionView: UICollectionView, dragSessionDidEnd session: UIDragSession) {
var removeItems = [IndexPath]()
for section in 0..<data.count {
for item in 0..<data[section].count {
switch data[section][item] {
case .availableToDropAtEnd:
removeItems.append(IndexPath(item: item, section: section))
case .simple:
break
}
}
}
removeItems.forEach { data[$0.section].remove(at: $0.item) }
collectionView.deleteItems(at: removeItems)
}
}
extension SecondController: UICollectionViewDropDelegate {
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
let destinationIndexPath: IndexPath
if let indexPath = coordinator.destinationIndexPath {
destinationIndexPath = indexPath
} else {
// useless, just in case
let section = collectionView.numberOfSections - 1
let row = collectionView.numberOfItems(inSection: section)
destinationIndexPath = IndexPath(row: row, section: section)
}
switch coordinator.proposal.operation {
case .move:
reorderItems(coordinator: coordinator, destinationIndexPath:destinationIndexPath, collectionView: collectionView)
default:
break
}
}
func collectionView(_ collectionView: UICollectionView, canHandle session: UIDropSession) -> Bool {
return true
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
// made the above logic useless
if collectionView.hasActiveDrag, destinationIndexPath != nil {
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
else {
return UICollectionViewDropProposal(operation: .forbidden)
}
}
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,
let localObject = item.dragItem.localObject as? CellModel {
collectionView.performBatchUpdates ({
data[sourceIndexPath.section].remove(at: sourceIndexPath.item)
data[destinationIndexPath.section].insert(localObject, at: destinationIndexPath.item)
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIndexPath])
})
}
}
}
Run Code Online (Sandbox Code Playgroud)
看法:
import UIKit
class CollectionViewCell: UICollectionViewCell {
weak var label: UILabel?
override init(frame: CGRect) {
super.init(frame: frame)
clipsToBounds = true
let label = UILabel(frame: .zero)
label.contentMode = .scaleAspectFill
addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
label.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
label.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
label.textAlignment = .center
label.textColor = .white
self.label = label
layer.borderWidth = 1
layer.borderColor = UIColor.white.cgColor
backgroundColor = .white
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func prepareForReuse() {
super.prepareForReuse()
label?.text = nil
backgroundColor = .white
}
}
class SupplementaryView: UICollectionReusableView {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.blue.withAlphaComponent(0.7)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Run Code Online (Sandbox Code Playgroud)