6
votes

I recently study collection view. I need to let some cells fix in their own index path, which mean they should not be exchanged by others and not be dragged. I now can use *- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath )indexPath to prevent them from dragging. I cannot prevent them from being exchanged by other cells.

Any one meet same issue?

Thanks

4
We will need more context in order to help you. Can you provide a schema or a XIB file illustrating the layout you want to achieve concerning the cells. Do they (the one that don't move) have specific position?user7219266

4 Answers

9
votes
func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
    if proposedIndexPath.row == data.count {
        return IndexPath(row: proposedIndexPath.row - 1, section: proposedIndexPath.section)
    } else {
        return proposedIndexPath
    }
}
4
votes

I found that when I used iOS 11+ drag and drop, targetIndexPathForMoveFromItemAt wouldn't get called. Implementing this method forbids the item from being dropped where I don't want it:

func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
    // disallow dragging across sections
    guard let sourcePath = session.items.first?.localObject as? IndexPath,
        let destPath = destinationIndexPath,
        sourcePath.section == destPath.section
        else {
            return UICollectionViewDropProposal(operation: .forbidden)
    }
    return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}

Note that I stored the source index path in localObject when the drag started, because I couldn't find a way to get this information otherwise.

3
votes

In this example you can't move the first and last component of your array in your CollectionView You can use porposedIndexPath, this is for UiCollectionView delegate

Swift 3

   func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
                if proposedIndexPath.row == 0 ||   proposedIndexPath.row == yourArray.count - 1{
                    return IndexPath(row: 1, section: 0)
                }
                return proposedIndexPath
            }
1
votes

Try using collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath

See Apple's docs: https://developer.apple.com/documentation/uikit/uicollectionviewdelegate/1618052-collectionview

During the interactive moving of an item, the collection view calls this method to see if you want to provide a different index path than the proposed path. You might use this method to prevent the user from dropping the item in an invalid location. For example, you might prevent the user from dropping the item in a specific section.

So for example, if you wanted to prevent reordering a cell with the last cell you could do:

func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
    if proposedIndexPath.row == data.count {
        return IndexPath(row: proposedIndexPath.row - 1, section: proposedIndexPath.section)
    } else {
        return proposedIndexPath
    }
}