【问题标题】:Centered paging on vertical UICollectionView with custom cell height在具有自定义单元格高度的垂直 UICollectionView 上居中分页
【发布时间】:2020-05-01 00:38:00
【问题描述】:

我看到很多帖子都解决了这个问题,但是,我在实现垂直集合视图的解决方案时遇到了麻烦。

我的集合视图的单元格填充了集合视图的整个宽度,但没有填满集合视图的整个高度,因此无法正常分页。我试图在使用自定义UICollectionViewFlowLayout 滚动时将单元格中心捕捉到屏幕中心。 (类似于 Instagram 提要,但没有“免费”滚动并且帖子垂直居中)

class FeedLayout: UICollectionViewFlowLayout {

    private var previousOffset: CGFloat = 0
    private var currentPage: Int = 0

    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        guard let collectionView = collectionView else {
            return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
        }

        let itemsCount = collectionView.numberOfItems(inSection: 0)
        if previousOffset > collectionView.contentOffset.y {
            currentPage = max(currentPage - 1, 0)
        } else if previousOffset < collectionView.contentOffset.y {
            currentPage = min(currentPage + 1, itemsCount - 1)
        }

        let updatedOffset = ((collectionView.frame.height * 0.75) + minimumLineSpacing) * CGFloat(currentPage)
        previousOffset = updatedOffset
        return CGPoint(x: proposedContentOffset.x, y: updatedOffset)
    }

}

【问题讨论】:

    标签: ios swift uicollectionview uikit uicollectionviewlayout


    【解决方案1】:

    几天前我写了一个开源的extension

    我会调整它以使单元格居中(而不是逐个单元格滚动,顶部有新单元格):

    public extension UICollectionViewFlowLayout {
        override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    
            guard let collectionView = self.collectionView else {
                let latestOffset = super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
                return latestOffset
            }
    
            // page height used for estimating and calculating paging
            let pageHeight = self.itemSize.height + self.minimumLineSpacing
    
            // determine total pages
            // collectionView adds an extra self.minimumLineSpacing to the total contentSize.height so this must be removed to get an even division of pages
            let totalPages = (collectionView.contentSize.height - self.minimumLineSpacing) / pageHeight
    
            // determine current page index
            let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
            let visiblePoint = self.itemSize.height * 2 > collectionView.visibleSize.height ? CGPoint(x: visibleRect.midX, y: visibleRect.midY) : CGPoint(x: visibleRect.midX, y: visibleRect.midY - (self.itemSize.height / 3))
            let visibleIndexPath = collectionView.indexPathForItem(at: visiblePoint)?.row ?? 0
            let currentIndex = CGFloat(visibleIndexPath)
    
            // make an estimation of the current page position
            let approximatePage = collectionView.contentOffset.y / pageHeight
    
            // determine the current page based on velocity
            let currentPage = velocity.y == 0 ? round(approximatePage) : (velocity.y < 0.0 ? floor(approximatePage) : ceil(approximatePage))
    
            // create custom flickVelocity
            let flickVelocity = velocity.y * 0.5
    
            // check how many pages the user flicked, if <= 1 then flickedPages should return 0
            let flickedPages = (abs(round(flickVelocity)) <= 1) ? 0 : round(flickVelocity)
    
            // determine the new vertical offset
            // scroll to top of next/previos cell
    //        let newVerticalOffset = ((currentPage + flickedPages) * pageHeight) - collectionView.contentInset.top
            // scroll to center of next/previous cell
            let newVerticalOffset = ((currentPage + flickedPages) * pageHeight) + ((collectionView.visibleSize.height - pageHeight) / 2) - collectionView.contentInset.top
    
            // determine up or down swipe
            let swipeDirection: CGFloat = flickVelocity > 0 ? 1 : -1
    
            // determine if we are at the end of beginning of list
            let beyond = newVerticalOffset + pageHeight >= collectionView.contentSize.height || collectionView.contentOffset.y < 0 ? true : false
    
            // determine if the flick was too small to switch pages
            let stay = abs(newVerticalOffset - collectionView.contentOffset.y) < (self.itemSize.height * 0.4) ? true : false
    
            // determine if there are multiple pages available to swipe based on current page
            var multipleAvailable = false
            if flickVelocity > 0 {
                multipleAvailable = currentIndex + swipeDirection < totalPages - 1 ? true : false
            } else {
                multipleAvailable = currentIndex + swipeDirection > 0 ? true : false
            }
    
            // give haptic feedback based on how many cells are scrolled
            if beyond == false && stay == false {
                if abs(flickedPages) > 1 && multipleAvailable {
                    TapticGenerator.notification(.success)
                } else {
                    TapticGenerator.impact(.medium)
                }
            }
    
            return CGPoint(x: proposedContentOffset.x, y: newVerticalOffset - collectionView.safeAreaInsets.top)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-01
      • 2010-09-22
      • 1970-01-01
      • 2021-07-10
      • 2012-03-03
      • 1970-01-01
      相关资源
      最近更新 更多