targetContentOffsetForProposedContentOffset - 错误的建议偏移量

targetContentOffsetForProposedContentOffset - wrong proposed offset

我有一个自定义 UICollectionViewLayout,它实现了 targetContentOffsetForProposedContentOffset 以设置分页。 UICollectionView 中的中心项目是完整的 "large" 尺寸,而其他项目的 CGAffineTransformScale 比例值为 "shrunk"。

我的问题是 contentOffset 似乎有上限,因此我只能滚动到第 5 项(共 7 项),然后它又弹回了。具体代码后:

我将 collectionViewContentSize() 设置如下:

@IBInspectable var shrunkScale: CGFloat = 0.5 // 0.5 in IB
@IBInspectable var largeSize: CGSize = CGSizeZero // 360x490 in IB
@IBInspectable var itemSpacing: CGFloat = 0 // 32 in IB

var widthPerAdditionalItem: CGFloat {
    return largeSize.width * shrunkScale + itemSpacing
}

override func collectionViewContentSize() -> CGSize {
    guard let collectionView = self.collectionView else {
        return CGSizeZero
    }

    let count = CGFloat(collectionView.numberOfItemsInSection(0))

    let width = largeSize.width + (count) * widthPerAdditionalItem
    let height = collectionView.bounds.height

    let size = CGSize(width: width, height: height)

    return size
}

targetOffset... 方法引用单个辅助方法:

override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint) -> CGPoint {

    let closestPlace = round(proposedContentOffset.x / widthPerAdditionalItem)

    guard let offsetX = offsetXForItemAtIndex(Int(closestPlace)) else {
        return proposedContentOffset
    }
    print("Calculated: \(offsetX), Proposed: \(proposedContentOffset.x), ContentWidth: \(collectionView?.contentSize.width ?? 0 )")
    return CGPoint(x: offsetX, y: proposedContentOffset.y)
}

override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    return targetContentOffsetForProposedContentOffset(proposedContentOffset)
}

func contentOffsetForItemAtIndexPath(indexPath: NSIndexPath) -> CGPoint? {
    guard
        let collectionView = self.collectionView,
        let offsetX =  offsetXForItemAtIndex(indexPath.item)
    else {
        return nil
    }
    print("Tap Offset: - \(offsetX) vs. \(collectionView.contentOffset.x)")
    return CGPoint(x: offsetX, y: collectionView.contentOffset.y)

}

private func offsetXForItemAtIndex(index: Int) -> CGFloat? {
    guard
        let count = collectionView?.numberOfItemsInSection(0)
    else {
        return nil
    }

    let proposed =  CGFloat(index) * widthPerAdditionalItem
    let maximum = CGFloat(count) * widthPerAdditionalItem

    // bound min = 0, max = count*width
    return max( min(maximum, proposed), 0)
}

这是我得到的:

  1. 我的内容宽度是1844.0
  2. 我在 offset.x = 1187.5
  3. 完成视图拖动
  4. targetContentOffsetForProposedContentOffset 收到建议 offset.x = 820.0
  5. 我return"paged"offset.x值848.0
  6. collectionView 滚动到 offset.x of 820.0

我期待的是:

  1. 我的内容宽度是1844.0
  2. 我在 offset.x = 1187.5
  3. 完成视图拖动
  4. targetContentOffsetForProposedContentOffset收到一个 建议 offset.x = 1187.5
  5. 我return"paged"offset.x值1272.0
  6. collectionView 滚动到 offset.x of 1272.0

调试中:

如果我手动调用 setContentOffset 并计算出 1272.0 的偏移量,那么它会滚动到正确的位置。但是在我尝试滚动它的那一刻,它突然回到 820.0

坐下来做一些数学计算后,我得出以下结论:

contentWidth = 1844
poposedContentOffset.x = 820
1844 - 820 = 1024 // <--- Width of the screen.

内容从第一项屏幕的中心显示到center 第二个项目的屏幕。

这意味着我需要添加一半的 collectionView frame.width 以便第一个项目可以居中,然后再添加一半以便最后一个项目可以居中。

collectionViewContentSize()现在returns

let width = (count-1) * widthPerAdditionalItem + collectionView.bounds.width
let height = collectionView.bounds.height
let size = CGSize(width: width, height: height)