Ken Chen
Ken Chen

Reputation: 121

UICollectionView, how to prevent one cell from being moved

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

Upvotes: 8

Views: 5554

Answers (4)

sv_lane
sv_lane

Reputation: 3089

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.

Upvotes: 5

Sharad Paghadal
Sharad Paghadal

Reputation: 2154

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
    }
}

Upvotes: 10

Victor Lagunas
Victor Lagunas

Reputation: 193

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
            }

Upvotes: 3

Alexandre G
Alexandre G

Reputation: 1693

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
    }
}

Upvotes: 2

Related Questions