Preventing moving UICollectionViewCell by its center when dragging
ios9, uicollectionview, uicollectionviewcell
Solution
(Written in Swift 3.1)
For the `targetPosition` parameter of the `updateInteractiveMovementTargetPosition` function, instead of using the gesture recognizer's location directly like this...
var location = recognizer.location(in: collectionView)
collectionView.updateInteractiveMovementTargetPosition(location)
... I created a function that takes the center of the cell to be dragged (The location that the collectionView `updateInteractiveMovementTargetPosition` would use, and then takes the location of the gesture recognizer's touch in the cell, and subtracts that from the center of the cell.
func offsetOfTouchFrom(recognizer: UIGestureRecognizer, inCell cell: UICollectionViewCell) -> CGPoint {
let locationOfTouchInCell = recognizer.location(in: cell)
let cellCenterX = cell.frame.width / 2
let cellCenterY = cell.frame.height / 2
let cellCenter = CGPoint(x: cellCenterX, y: cellCenterY)
var offSetPoint = CGPoint.zero
offSetPoint.y = cellCenter.y - locationOfTouchInCell.y
offSetPoint.x = cellCenter.x - locationOfTouchInCell.x
return offSetPoint
}
I have a simple `var offsetForCollectionViewCellBeingMoved: CGPoint = .zero` in my view controller that will store that offset so function above doesn't need to be called every time the gesture recognizer's location changes.
So the target of my gesture recognizer would look like this:
func collectionViewLongPressGestureRecognizerWasTriggered(recognizer: UILongPressGestureRecognizer) {
guard let indexPath = collectionView.indexPathForItem(at: recognizer.location(in: self.collectionView)),
let cell = collectionView.cellForItem(at: indexPath), indexPath.item != 0 else { return }
switch recognizer.state {
case .began:
collectionView.beginInteractiveMovementForItem(at: indexPath)
// This is the class variable I mentioned above
offsetForCollectionViewCellBeingMoved = offsetOfTouchFrom(recognizer: recognizer, inCell: cell)
// This is the vanilla location of the touch that alone would make the cell's center snap to your touch location
var location = recognizer.location(in: collectionView)
/* These two lines add the offset calculated a couple lines up to
the normal location to make it so you can drag from any part of the
cell and have it stay where your finger is. */
location.x += offsetForCollectionViewCellBeingMoved.x
location.y += offsetForCollectionViewCellBeingMoved.y
collectionView.updateInteractiveMovementTargetPosition(location)
case .changed:
var location = recognizer.location(in: collectionView)
location.x += offsetForCollectionViewCellBeingMoved.x
location.y += offsetForCollectionViewCellBeingMoved.y
collectionView.updateInteractiveMovementTargetPosition(location)
case .ended:
collectionView.endInteractiveMovement()
default:
collectionView.cancelInteractiveMovement()
}
}
Problem
I am able to reorder my UICollectionViewCells on iOS 9 by dragging it using a gesture recognizer and simplementing newly iOS 9 support for reordering. ``` public func beginInteractiveMovementForItemAtIndexPath(indexPath: NSIndexPath) -> Bool // returns NO if reordering was prevented from beginning - otherwise YES public func updateInteractiveMovementTargetPosition(targetPosition: CGPoint) public func endInteractiveMovement() public func cancelInteractiveMovement() ``` I noticed that when I start dragging a cell, its center changes to be the touch location, I don't like that. I would like to be able to drag my cell by it's corner if I want. Do you know how to do this? Thanks a lot.