具有自定义anchorPoint的UICollectionViewFlowLayout单元格过早重用

时间:2016-06-23 18:12:04

标签: ios swift uicollectionview

我已经将UICollectionViewFlowLayout子类化,以在水平滚动期间实现小的缩放效果。因此,我必须继承UICollectionViewCell以及更改单元格的layer.anchorPoint(我的缩放是从单元格的左下角而不是默认中心)。现在一切都很好,除了我水平滚动的时候,我的细胞很快就被重复使用了(当它突然消失时,我仍然可以看到半细胞)。

我觉得集合视图的基础仍然是重复使用位于单元中心的锚点上的单元格...

但是,这是我的集合视图。您可以看到项目在到达集合视图左侧时变大的方式。这是我想要的缩放。 enter image description here

现在我在这里滚动到左边。你可以看到正确的项目如何变得更大,左边是如何离开屏幕。 enter image description here

在这里你看到左边的项目没有离开屏幕但已经消失了。只有正确的项目可见:/ enter image description here

所以我想要的是,只有当它的右边界到达屏幕的最左边时才使左项消失。简单地说,只有当我不再看到它时才消失。< / p>

这是我的代码:

class SongsCollectionViewCell : UICollectionViewCell {

@IBOutlet weak var imgAlbumCover: UIImageView!


override func applyLayoutAttributes(layoutAttributes: UICollectionViewLayoutAttributes) {
    super.applyLayoutAttributes(layoutAttributes)

    //we must change the anchor point for propper cells positioning and scaling
    self.layer.anchorPoint.x = 0
    self.layer.anchorPoint.y = 1
}

}

这是布局本身:

class SongsCollectionViewLayout : UICollectionViewFlowLayout {

override func prepareLayout() {
    collectionView?.decelerationRate = UIScrollViewDecelerationRateFast
    self.scrollDirection = UICollectionViewScrollDirection.Horizontal;

    //size of the viewport
    let size:CGSize = self.collectionView!.frame.size;
    let itemWidth:CGFloat  = size.width * 0.7//0.7//3.0;
    self.itemSize = CGSizeMake(itemWidth, itemWidth);
    self.sectionInset = UIEdgeInsetsMake(0,0,0,0);
    self.minimumLineSpacing = 0
    self.minimumInteritemSpacing = 0

}

override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
    return true
}


override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

    let attributes:[UICollectionViewLayoutAttributes] = super.layoutAttributesForElementsInRect(rect)!

    var visibleRect:CGRect = CGRect()
    visibleRect.origin = self.collectionView!.contentOffset;
    visibleRect.size = self.collectionView!.bounds.size;

    for layoutAttributes in attributes {

        if (CGRectIntersectsRect(layoutAttributes.frame, rect)) {

            //we must align items to the bottom of the collection view on y axis
            let frameHeight = self.collectionView!.bounds.size.height
            layoutAttributes.center.y = frameHeight
            layoutAttributes.center.x = layoutAttributes.center.x - self.itemSize.width/2

            //find where ite, left x is
            let itemLeftX:CGFloat = layoutAttributes.center.x

            //distance of the item from the left of the viewport
            let distanceFromTheLeft:CGFloat = itemLeftX - CGRectGetMinX(visibleRect)
            let normalizedDistanceFromTheLeft = abs(distanceFromTheLeft) / self.collectionView!.frame.size.width

            //item that is closer to the left is most visible one
            layoutAttributes.alpha = 1 - normalizedDistanceFromTheLeft
            layoutAttributes.zIndex = abs(Int(layoutAttributes.alpha)) * 10;

            //scale items
            let scale =  min(layoutAttributes.alpha + 0.5, 1)
            layoutAttributes.transform = CGAffineTransformMakeScale(scale, scale)

        }

    }

    return attributes;
}

override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    // Snap cells to centre
    var newOffset = CGPoint()
    let layout = collectionView!.collectionViewLayout as! UICollectionViewFlowLayout
    let width = layout.itemSize.width + layout.minimumLineSpacing
    var offset = proposedContentOffset.x + collectionView!.contentInset.left

    if velocity.x > 0 {
        //ceil returns next biggest number
        offset = width * ceil(offset / width)
    } else if velocity.x == 0 { //6
        //rounds the argument
        offset = width * round(offset / width)
    } else if velocity.x < 0 { //7
        //removes decimal part of argument
        offset = width * floor(offset / width)
    }
    newOffset.x = offset - collectionView!.contentInset.left
    newOffset.y = proposedContentOffset.y //y will always be the same...
    return newOffset
}

}

1 个答案:

答案 0 :(得分:2)

回答我自己的问题。 因此,我怀疑,布局考虑了一个旧的中心,这就是为什么我必须在更改锚点后立即纠正单元格的中心。所以我的自定义单元格现在看起来像这样:

class SongsCollectionViewCell : UICollectionViewCell {

@IBOutlet weak var imgAlbumCover: UIImageView!

override func prepareForReuse() {
    imgAlbumCover.hnk_cancelSetImage()
    imgAlbumCover.image = nil
}

override func applyLayoutAttributes(layoutAttributes: UICollectionViewLayoutAttributes) {
    super.applyLayoutAttributes(layoutAttributes)

    //we must change the anchor point for propper cells positioning and scaling
    self.layer.anchorPoint.x = 0
    self.layer.anchorPoint.y = 1

    //we need to adjust a center now
    self.center.x = self.center.x - layoutAttributes.size.width/2
}

}

希望它有助于某人