我正在学习 UICollectionView,我正在处理一个 collectionview 中各部分之间的单元格拖放操作
当一个部分中的元素数量多于部分的总数时,我遇到了问题
Fatal error: Index out of range
我不知道我是否正确声明了二维数组,谁能帮我解决代码的正确部分?
ViewController 中的代码
class ExampleViewController: UIViewController {
@IBOutlet var collectionView: UICollectionView!
private let minimumLineSpacing: CGFloat = 1
private let minimumInteritemSpacing: CGFloat = 1
private let numberOfItemInRow: CGFloat = 3
private var numbers: [[Int]] = [
[Int](1...9),
[Int](2...3),
[Int](1...2),
[Int](4...7),
[Int](5...9),
[Int](3...5),
]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
configCollectionView(collectionView)
print(numbers)
// uncomment to avoid conflict with Long Tap handler
// configDragDropGesture()
configDoubleTapGesture()
configLongTapGesture()
}
}
// MARK: - configCollectionView ExampleViewController
extension ExampleViewController {
func configCollectionView(_ collectionView: UICollectionView) {
collectionView.register(
.init(nibName: "\(ExampleCell.self)", bundle: nil),
forCellWithReuseIdentifier: "\(ExampleCell.self)")
collectionView.register(
.init(nibName: "\(ExampleHeaderReuseableView.self)", bundle: nil),
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: "\(ExampleHeaderReuseableView.self)")
collectionView.register(
.init(nibName: "\(ExampleFooterReusableView.self)", bundle: nil),
forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter,
withReuseIdentifier: "\(ExampleFooterReusableView.self)")
collectionView.delegate = self
collectionView.dataSource = self
collectionView.dragDelegate = self
collectionView.dropDelegate = self
collectionView.reorderingCadence = .fast
collectionView.dragInteractionEnabled = true
}
}
// MARK: - UICollectionViewDragDelegate
extension ExampleViewController: 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 = numbers[indexPath.section][indexPath.row]
print(Self.self, #function)
return [dragItem]
}
}
// MARK: - UICollectionViewDropDelegate
extension ExampleViewController: 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 {
reOrderItems(collectionView: collectionView,
coordinator: coordinator,
destinationIndexPath: destinationIndexPath)
}
}
}
// MARK: - ExampleViewController reOrderItems
extension ExampleViewController {
func reOrderItems(collectionView: UICollectionView,
coordinator: UICollectionViewDropCoordinator,
destinationIndexPath: IndexPath)
{
if let item = coordinator.items.first,
let sourceIndexPath = item.sourceIndexPath
{
collectionView.performBatchUpdates({
print("origin arr: ", numbers)
self.numbers[sourceIndexPath.section].remove(at: sourceIndexPath.item)
print("after remove: ", numbers)
self.numbers[destinationIndexPath.section].insert((item.dragItem.localObject as? Int)!,
at: destinationIndexPath.item)
print("after insert: ", numbers)
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIndexPath])
}, completion: nil)
coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
}
}
}
// MARK: - UICollectionViewDelegate
extension ExampleViewController: UICollectionViewDelegate {
// Handle Tap Action
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath)
{
presentAlert(withTitle: "Single Tap",
message: "You tapped at index: \(indexPath.row)",
actionTitle: "OK",
style: .default)
}
// Handle Header - Footer
func collectionView(_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String,
at indexPath: IndexPath) -> UICollectionReusableView
{
switch kind {
case UICollectionView.elementKindSectionHeader:
if let headerView = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: "\(ExampleHeaderReuseableView.self)",
for: indexPath) as? ExampleHeaderReuseableView
{
headerView.backgroundColor = .magenta
headerView.bindData(indexPath)
return headerView
}
case UICollectionView.elementKindSectionFooter:
if let footerView = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: "\(ExampleFooterReusableView.self)",
for: indexPath) as? ExampleFooterReusableView
{
footerView.backgroundColor = .cyan
footerView.bindData(indexPath)
return footerView
}
default:
return UICollectionReusableView()
}
return UICollectionReusableView()
}
}
// MARK: - UICollectionViewDataSource
extension ExampleViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
print(Self.self, #function)
return true
}
func collectionView(_ collectionView: UICollectionView,
moveItemAt sourceIndexPath: IndexPath,
to destinationIndexPath: IndexPath)
{
let item = numbers.remove(at: sourceIndexPath.row)
numbers.insert(item, at: destinationIndexPath.row)
print(Self.self, #function)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return numbers.count
}
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int
{
return numbers[section].count
}
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "\(ExampleCell.self)",
for: indexPath) as! ExampleCell
cell.bindData(numbers[indexPath.row], indexPath)
return cell
}
}
文件单元格中的代码
class ExampleCell: UICollectionViewCell {
@IBOutlet weak var titleLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
// MARK: - Func bindData ExampleCell
extension ExampleCell {
func bindData(_ number: [Int],_ indexPath: IndexPath) {
titleLabel.text = "\(number) - \(indexPath.section)"
}
}
我正在使用 indexpath 在 collectionview 上显示