I have a collectionView I am able to zoom when pinched.
It works like this:
I added a UIPinchGestureRecognizer on collectionView, when a pinch occurs I invalidate layout which force collectionView to ask delegate for new size.
It works well.
The problem I am unable to fix is that during pinch I want to keep my cell at same position. Just under the indicator at the middle of the screen. (see screenshot).
I was thinking to store current scrollView offset when pinch begins then when cell are redisplayed with new size, I calculate width difference and add or substract to contentOffset.
I have a contentInset in order to scroll first cell at the middle on the collectionView.
Here is my code:
@objc func handlePinchGesture(gesture: UIPinchGestureRecognizer) {
if (gesture.state == .Began) {
scaleStart = metrics.scale // remember current scale
widthStart = collectionView.visibleCells()\[0\].bounds.width // get size of a cell to calulate a difference when scale will change
originalContentOffset = collectionView.contentOffset.x // remember original content offset
}
else if (gesture.state == .Changed) {
let newScale = metrics.normalizeScale(scaleStart * gesture.scale) // normalize scale. give 0.5, 1, 1.5, 2
metrics.scale = newScale // global struct
//let ZoomIn = (newScale > scaleStart)
collectionView.collectionViewLayout.invalidateLayout() // invalidate layout in order to redisplay cell with updated scale
let scaleRatio = newScale / self.scaleStart
var newContentOffset = CGFloat(0)
let widthDiff: CGFloat = (scaleRatio * self.widthStart) - self.widthStart
newContentOffset = originalContentOffset + widthDiff
self.collectionView.setContentOffset(CGPointMake(newContentOffset ,0), animated: false)
}
}
It just doest not work...
Do you have an idea?
Thanks a lot for your input.
Here is a screenshot of what I have and want with correct offsets. But I am unable to find a correct way to calculate content offset after pinch gesture.
Thierry
Regarding your original question, where you want the zoom center be at the middle of the screen, try this:
@objc func handlePinchGesture(_ gesture: UIPinchGestureRecognizer) {
let scaleValue: CGFloat = gesture.scale
if (gesture.state == .began) {
scaleStart = metrics.scale // remember current scale
widthStart = collectionView.visibleCells[0].bounds.width // get size of a cell to calulate a difference when scale will change
originalContentOffset = collectionView.contentOffset.x // remember original content offset
originalNumberOfCellsToOffset = (originalContentOffset + (self.view.frame.size.width/2)) / (widthStart * 2) //for zooming at the middle of the screen
}
else if (gesture.state == .changed) {
let newScale = scaleStart * gesture.scale
//let newScale = metrics.normalizeScale(scaleStart * gesture.scale) // use this line instead, if you want to normalize scale. give 0.5, 1, 1.5, 2
metrics.scale = newScale // global struct
//let ZoomIn = (newScale > scaleStart)
collectionView.collectionViewLayout.invalidateLayout() // invalidate layout in order to redisplay cell with updated scale
let scaleRatio = newScale / scaleStart
var newContentOffset = CGFloat(0)
let offsetDiffForEachCell: CGFloat = (scaleRatio * widthStart) - widthStart
newContentOffset = (offsetDiffForEachCell)*originalNumberOfCellsToOffset + (originalContentOffset)
collectionView.setContentOffset(CGPoint(x: newContentOffset ,y: 0), animated: false)
}
}
Depending on the position and size of the collectionView on your screen, it might not be really zooming at the middle of the screen. If that's the case, what you want to do is to change this line:
originalNumberOfCellsToOffset = (originalContentOffset + (self.view.frame.size.width/2)) / (widthStart * 2) //for zooming at the middle of the screen
to e.g.
originalNumberOfCellsToOffset = (originalContentOffset + (self.view.frame.size.width/2) - 20) / (widthStart * 2) //for zooming at the middle of the screen
if you want the zoom center to be 20px more to the left.
BONUS: If instead, you want to zoom at the middle of the pinch, then change this line:
originalNumberOfCellsToOffset = (originalContentOffset + (self.view.frame.size.width/2)) / (widthStart * 2) //for zooming at the middle of the screen
to
originalNumberOfCellsToOffset = (gesture.location(ofTouch: 0, in: sectionSequenceCollectionView).x + gesture.location(ofTouch: 1, in: sectionSequenceCollectionView).x) / (widthStart * 2)
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