Paging UICollectionView by cells, not screen

前端 未结 22 1944
予麋鹿
予麋鹿 2020-12-04 05:00

I have UICollectionView with horizontal scrolling and there are always 2 cells side-by-side per the entire screen. I need the scrolling to stop at the begining

相关标签:
22条回答
  • 2020-12-04 05:45

    Here is my version of it in Swift 3. Calculate the offset after scrolling ended and adjust the offset with animation.

    collectionLayout is a UICollectionViewFlowLayout()

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let index = scrollView.contentOffset.x / collectionLayout.itemSize.width
        let fracPart = index.truncatingRemainder(dividingBy: 1)
        let item= Int(fracPart >= 0.5 ? ceil(index) : floor(index))
    
        let indexPath = IndexPath(item: item, section: 0)
        collectionView.scrollToItem(at: indexPath, at: .left, animated: true)
    }
    
    0 讨论(0)
  • 2020-12-04 05:47

    OK, so I found the solution here: targetContentOffsetForProposedContentOffset:withScrollingVelocity without subclassing UICollectionViewFlowLayout

    I should have searched for targetContentOffsetForProposedContentOffset in the begining.

    0 讨论(0)
  • 2020-12-04 05:47

    Swift 3 version of Evya's answer:

    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
      targetContentOffset.pointee = scrollView.contentOffset
        let pageWidth:Float = Float(self.view.bounds.width)
        let minSpace:Float = 10.0
        var cellToSwipe:Double = Double(Float((scrollView.contentOffset.x))/Float((pageWidth+minSpace))) + Double(0.5)
        if cellToSwipe < 0 {
            cellToSwipe = 0
        } else if cellToSwipe >= Double(self.articles.count) {
            cellToSwipe = Double(self.articles.count) - Double(1)
        }
        let indexPath:IndexPath = IndexPath(row: Int(cellToSwipe), section:0)
        self.collectionView.scrollToItem(at:indexPath, at: UICollectionViewScrollPosition.left, animated: true)
    
    
    }
    
    0 讨论(0)
  • 2020-12-04 05:48

    Here's the easiest way that i found to do that in Swift 4.2 for horinzontal scroll:

    I'm using the first cell on visibleCells and scrolling to then, if the first visible cell are showing less of the half of it's width i'm scrolling to the next one.

    If your collection scroll vertically, simply change x by y and width by height

    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        targetContentOffset.pointee = scrollView.contentOffset
        var indexes = self.collectionView.indexPathsForVisibleItems
        indexes.sort()
        var index = indexes.first!
        let cell = self.collectionView.cellForItem(at: index)!
        let position = self.collectionView.contentOffset.x - cell.frame.origin.x
        if position > cell.frame.size.width/2{
           index.row = index.row+1
        }
        self.collectionView.scrollToItem(at: index, at: .left, animated: true )
    }
    
    0 讨论(0)
  • 2020-12-04 05:49

    Partly based on StevenOjo's answer. I've tested this using a horizontal scrolling and no Bounce UICollectionView. cellSize is CollectionViewCell size. You can tweak factor to modify scrolling sensitivity.

    override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        targetContentOffset.pointee = scrollView.contentOffset
        var factor: CGFloat = 0.5
        if velocity.x < 0 {
            factor = -factor
        }
        let indexPath = IndexPath(row: (scrollView.contentOffset.x/cellSize.width + factor).int, section: 0)
        collectionView?.scrollToItem(at: indexPath, at: .left, animated: true)
    }
    
    0 讨论(0)
  • 2020-12-04 05:51

    Approach 1: Collection View

    flowLayout is UICollectionViewFlowLayout property

    override func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    
        if let collectionView = collectionView {
    
            targetContentOffset.memory = scrollView.contentOffset
            let pageWidth = CGRectGetWidth(scrollView.frame) + flowLayout.minimumInteritemSpacing
    
            var assistanceOffset : CGFloat = pageWidth / 3.0
    
            if velocity.x < 0 {
                assistanceOffset = -assistanceOffset
            }
    
            let assistedScrollPosition = (scrollView.contentOffset.x + assistanceOffset) / pageWidth
    
            var targetIndex = Int(round(assistedScrollPosition))
    
    
            if targetIndex < 0 {
                targetIndex = 0
            }
            else if targetIndex >= collectionView.numberOfItemsInSection(0) {
                targetIndex = collectionView.numberOfItemsInSection(0) - 1
            }
    
            print("targetIndex = \(targetIndex)")
    
            let indexPath = NSIndexPath(forItem: targetIndex, inSection: 0)
    
            collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Left, animated: true)
        }
    }
    

    Approach 2: Page View Controller

    You could use UIPageViewController if it meets your requirements, each page would have a separate view controller.

    0 讨论(0)
提交回复
热议问题