“targetContentOffset” UICollectionViewFlowLayout not working properly

会有一股神秘感。 提交于 2019-12-24 01:33:26

问题


I have a requirement to keep UICollectionViewCell center aligned in portrait mode.
Final result should be like : animation

I'm using this code to do this:

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)
}

This works fine for all cell except the last cell which doesn't get center aligned upon scrolling.

Actual result:

Is there any way to resolve this issue?


回答1:


To keep the UICollectionViewCell in center, you need to change the UICollectionViewFlowLayout of UICollectionView,i.e. make subclass of UICollectionViewFlowLayout and set it as UICollectionView's Layout in storyboard.

1. UICollectionViewFlowLayout subclass

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 methods

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
}

Check the above code and let me know if this satisfy your requirement.




回答2:


I found that if I set

collectionView.isPagingEnabled = true

it will broken the center cell setting. Once I turn it off, everything works fine again




回答3:


For subclass of 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)
}


来源:https://stackoverflow.com/questions/45614617/targetcontentoffset-uicollectionviewflowlayout-not-working-properly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!