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.
(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()
}
}
If your collection view is only scrolling in once direction then the easiest way to achieve this is to simple lock the axis which isnt scrolling to something hardcoded, this means your cell will only move in the axis that you can scroll. Here is the code, see the changed case...
@objc func handleLongGesture(gesture: UILongPressGestureRecognizer) {
switch gesture.state {
case .began:
guard let selectedIndexPath = self.collectionView
.indexPathForItem(at: gesture
.location(in: self.collectionView)) else { break }
collectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
case .changed:
var gesturePosition = gesture.location(in: gesture.view!)
gesturePosition.x = (self.collectionView.frame.width / 2) - 20
collectionView.updateInteractiveMovementTargetPosition(gesturePosition)
case .ended:
collectionView.endInteractiveMovement()
default:
collectionView.cancelInteractiveMovement()
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With