在捏缩放后保持collectionView单元格位置

thi*_*ryb 6 ios uicollectionview

我有一个collectionView,我可以在收缩时进行缩放.

它的工作原理如下:

我在collectionView上添加了一个UIPinchGestureRecognizer,当发生捏合时,我使布局无效,迫使collectionView向委托询问新的大小.

它运作良好.

我无法解决的问题是,在挤压期间我想让我的手机保持在同一位置.就在屏幕中间的指示器下方.(见截图).

我正在考虑在捏开始时存储当前的scrollView偏移,然后当以新的大小重新显示单元格时,我计算宽度差并添加或减去contentOffset.

我有一个contentInset,以便在collectionView的中间滚动第一个单元格.

这是我的代码:

@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)
    }
}
Run Code Online (Sandbox Code Playgroud)

它只是不起作用......

你有好主意吗?

非常感谢您的投入.

这是我所拥有和想要的正确偏移的屏幕截图.但我无法找到一种正确的方法来计算捏合手势后的内容偏移量.

截图

蒂埃里

小智 2

关于您最初的问题,您希望缩放中心位于屏幕中间,请尝试以下操作:

@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)
    }
}
Run Code Online (Sandbox Code Playgroud)

根据屏幕上 collectionView 的位置和大小,它可能不会真正在屏幕中间缩放。如果是这种情况,您要做的就是更改此行:

originalNumberOfCellsToOffset =  (originalContentOffset + (self.view.frame.size.width/2)) / (widthStart * 2)  //for zooming at the middle of the screen
Run Code Online (Sandbox Code Playgroud)

例如

originalNumberOfCellsToOffset =  (originalContentOffset + (self.view.frame.size.width/2) - 20) / (widthStart * 2)  //for zooming at the middle of the screen
Run Code Online (Sandbox Code Playgroud)

如果您希望缩放中心向左多 20px。


奖励:如果您想在捏合的中间进行缩放,请更改此行:

originalNumberOfCellsToOffset =  (originalContentOffset + (self.view.frame.size.width/2)) / (widthStart * 2)  //for zooming at the middle of the screen
Run Code Online (Sandbox Code Playgroud)

originalNumberOfCellsToOffset = (gesture.location(ofTouch: 0, in: sectionSequenceCollectionView).x + gesture.location(ofTouch: 1, in: sectionSequenceCollectionView).x) / (widthStart * 2)
Run Code Online (Sandbox Code Playgroud)