为什么collectionView单元中心只能在一个方向上工作?

时间:2016-05-20 07:06:12

标签: ios swift uicollectionview uicollectionviewcell uicollectionviewlayout

我正试图在水平卷轴上对我的细胞进行中心化。我写了一个方法,但只有当我向右滚动时,它才有效,在左侧滚动时它只是滚动,而不是停在单元格的中心。

有人可以帮我定义这个bug吗?

class CenterCellCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    if let cv = self.collectionView {
        let cvBounds = cv.bounds
        let halfWidth = cvBounds.size.width * 0.5;
        let proposedContentOffsetCenterX = proposedContentOffset.x + halfWidth;

        if let attributesForVisibleCells = self.layoutAttributesForElementsInRect(cvBounds) {
            var candidateAttributes: UICollectionViewLayoutAttributes?
            for attributes in attributesForVisibleCells {

                // == Skip comparison with non-cell items (headers and footers) == //
                if attributes.representedElementCategory != UICollectionElementCategory.Cell {
                    continue
                }

                if (attributes.center.x == 0) || (attributes.center.x > (cv.contentOffset.x + halfWidth) && velocity.x < 0) {
                    continue
                }

                // == First time in the loop == //
                guard let candAttrs = candidateAttributes else {
                    candidateAttributes = attributes
                    continue
                }

                let a = attributes.center.x - proposedContentOffsetCenterX
                let b = candAttrs.center.x - proposedContentOffsetCenterX

                if fabsf(Float(a)) < fabsf(Float(b)) {
                    candidateAttributes = attributes;
                }
            }

            if(proposedContentOffset.x == -(cv.contentInset.left)) {
                return proposedContentOffset
            }

             return CGPoint(x: floor(candidateAttributes!.center.x - halfWidth), y: proposedContentOffset.y)
        }
    } else {
        print("else")
    }

    // fallback
    return super.targetContentOffsetForProposedContentOffset(proposedContentOffset)
    }
}

在我的UIViewController中:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    var insets = self.collectionView.contentInset
    let value = ((self.view.frame.size.width - ((CGRectGetWidth(collectionView.frame) - 35))) * 0.5)
    insets.left = value
    insets.right = value
    self.collectionView.contentInset = insets

    self.collectionView.decelerationRate = UIScrollViewDecelerationRateNormal
}

如果您有任何疑问 - 请问我

1 个答案:

答案 0 :(得分:0)

我实际上只为另一个线程执行了稍微不同的实现,但调整它以适用于这个问题。试试下面的解决方案:)

/**
 *  Custom FlowLayout
 *  Tracks the currently visible index and updates the proposed content offset
 */
class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {

    // Tracks the currently visible index
    private var visibleIndex : Int = 0

    // The width offset threshold percentage from 0 - 1
    let thresholdOffsetPrecentage : CGFloat = 0.5

    // This is the flick velocity threshold
    let velocityThreshold : CGFloat = 0.4

    override init() {
        super.init()
        self.minimumInteritemSpacing = 0.0
        self.minimumLineSpacing = 0.0
        self.scrollDirection = .Horizontal
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

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

        let leftThreshold = CGFloat(collectionView!.bounds.size.width) * ((CGFloat(visibleIndex) - 0.5))
        let rightThreshold = CGFloat(collectionView!.bounds.size.width) * ((CGFloat(visibleIndex) + 0.5))

        let currentHorizontalOffset = collectionView!.contentOffset.x

        // If you either traverse far enough in either direction,
        // or flicked the scrollview over the horizontal velocity in either direction,
        // adjust the visible index accordingly

        if currentHorizontalOffset < leftThreshold || velocity.x < -velocityThreshold {
            visibleIndex = max(0 , (visibleIndex - 1))
        } else if currentHorizontalOffset > rightThreshold || velocity.x > velocityThreshold {
            visibleIndex += 1
        }

        var _proposedContentOffset = proposedContentOffset
        _proposedContentOffset.x = CGFloat(collectionView!.bounds.width) * CGFloat(visibleIndex)

        return _proposedContentOffset
    }
}