"targetContentOffset" UICollectionViewFlowLayout 无法正常工作

"targetContentOffset" UICollectionViewFlowLayout not working properly

我需要在纵向模式下保持 UICollectionViewCell 居中对齐。
最终结果应该是这样的: animation

我正在使用此代码来执行此操作:

override public func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {

var layoutAttributes: Array = layoutAttributesForElements(in: collectionView!.bounds)!

if layoutAttributes.count == 0 {
    return proposedContentOffset
}

var firstAttribute: UICollectionViewLayoutAttributes = layoutAttributes[0]

for attribute: UICollectionViewLayoutAttributes in layoutAttributes {
    if attribute.representedElementCategory != .cell {
        continue
    }

    if((velocity.x >= 0.0 && attribute.center.x > firstAttribute.center.x) ||
        (velocity.x <= 0.0 && attribute.center.x < firstAttribute.center.x)) {
        firstAttribute = attribute;
    }
}

return CGPoint(x: firstAttribute.center.x - 

collectionView!.bounds.size.width * 0.5, y: proposedContentOffset.y)
}

这适用于所有单元格,除了最后一个单元格在滚动时没有居中对齐。

实际结果:

有什么办法可以解决这个问题吗?

为了让UICollectionViewCell居中,你需要改变UICollectionViewUICollectionViewFlowLayout,即创建 UICollectionViewFlowLayout 的子类并将其设置为 UICollectionView's 布局 storyboard.

1. UICollectionViewFlowLayout 子类

class CollectionViewFlowLayout: UICollectionViewFlowLayout
{
    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint
    {
        if let collectionViewBounds = self.collectionView?.bounds
        {
            let halfWidthOfVC = collectionViewBounds.size.width * 0.5
            let proposedContentOffsetCenterX = proposedContentOffset.x + halfWidthOfVC
            if let attributesForVisibleCells = self.layoutAttributesForElements(in: collectionViewBounds)
            {
                var candidateAttribute : UICollectionViewLayoutAttributes?
                for attributes in attributesForVisibleCells
                {
                    let candAttr : UICollectionViewLayoutAttributes? = candidateAttribute
                    if candAttr != nil
                    {
                        let a = attributes.center.x - proposedContentOffsetCenterX
                        let b = candAttr!.center.x - proposedContentOffsetCenterX
                        if fabs(a) < fabs(b)
                        {
                            candidateAttribute = attributes
                        }
                    }
                    else
                    {
                        candidateAttribute = attributes
                        continue
                    }
                }

                if candidateAttribute != nil
                {
                    return CGPoint(x: candidateAttribute!.center.x - halfWidthOfVC, y: proposedContentOffset.y);
                }
            }
        }
        return CGPoint.zero
    }
}

2。 UICollectionViewDelegateFlowLayout 方法

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
    let cellSize = CGSize(width: collectionView.bounds.width - (2 * kCellSpacing) - (2 * kCellInset), height: collectionView.bounds.height)
    return cellSize
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
{
    return kCellSpacing
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
{
    let sectionInset = UIEdgeInsetsMake(0, kCellSpacing + kCellInset, 0, kCellSpacing + kCellInset)
    return sectionInset
}

检查上面的代码,让我知道这是否满足您的要求。

我发现如果我设置

collectionView.isPagingEnabled = true

它会破坏中心单元格设置。一旦我将其关闭,一切又恢复正常了

对于 UICollectionViewFlowLayout 的子类:

override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {
    guard let collectionView = self.collectionView
        else { return .zero }
    let horizontalcenter = proposedContentOffset.x + collectionView.bounds.width / 2.0

    let proposedRect = CGRect(x: proposedContentOffset.x, y: proposedContentOffset.y, width: collectionView.bounds.width, height: collectionView.bounds.height)
    var offsetAdjusment = CGFloat(MAXFLOAT)
    if let layoutAttributes = layoutAttributesForElements(in: proposedRect){

        for attributes in layoutAttributes{
            if attributes.representedElementCategory != UICollectionElementCategory.cell{
                continue
            }

            let itemHorizontalCenter = attributes.center.x
            if abs(itemHorizontalCenter - horizontalcenter) < abs(offsetAdjusment){
                offsetAdjusment = itemHorizontalCenter - horizontalcenter
            }
        }
    }

    return CGPoint(x: proposedContentOffset.x + offsetAdjusment, y: proposedContentOffset.y)
}