【问题标题】:Hide/show CollectionView's Header on scroll在滚动时隐藏/显示 CollectionView 的标题
【发布时间】:2023-03-08 14:35:01
【问题描述】:

我想在向上滚动时隐藏我的 collectionView 的 Header 单元格。一旦用户向下滚动一点,就会再次显示它。我使用UICollectionViewFlowLayout 尝试过,但没有成功。

class FilterHeaderLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    let layoutAttributes = super.layoutAttributesForElements(in: rect)
    var safeAreaTop = 0.0
    if #available(iOS 13.0, *) {
        let window = UIApplication.shared.windows.first
        safeAreaTop = window!.safeAreaInsets.top
    }
    
    layoutAttributes?.forEach({ attributes in
        if attributes.representedElementKind == UICollectionView.elementKindSectionHeader{
            
            guard let collectionView = collectionView else { return }
            
            let width = collectionView.frame.width
            let contentOfsetY = collectionView.contentOffset.y


            if contentOfsetY < 0 {
                //prevents header cell to drift away if user scroll all the way down
                
                // 41 is height of a view in navigation bar. header cell needs to be below navigation bar.
                attributes.frame = .init(x: 0, y: safeAreaTop+41+contentOfsetY, width: width, height: 50)
                return
            }
            
            let scrollVelocity = collectionView.panGestureRecognizer.velocity(in: collectionView.superview)
                if (scrollVelocity.y > 0.0) {
                    // show the header and make it stay at top
                } else if (scrollVelocity.y < 0.0) {
                    // hide the header
                }
            attributes.frame = .init(x: 0, y: safeAreaTop+41+contentOfsetY, width: width, height: 50)
        }
    })
    
    return layoutAttributes
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
    return true
}

}

【问题讨论】:

    标签: swift uicollectionview uikit uicollectionviewlayout


    【解决方案1】:

    那是代码很老了,但让我们试试吧:

        override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint,
                                      withScrollingVelocity velocity: CGPoint) -> CGPoint {
        
        var offsetAdjustment = CGFloat.greatestFiniteMagnitude
        let verticalOffset = proposedContentOffset.y
        let targetRect = CGRect(origin: CGPoint(x: 0, y: proposedContentOffset.y), size: self.collectionView!.bounds.size)
        
        for layoutAttributes in super.layoutAttributesForElements(in: targetRect)! {
            let itemOffset = layoutAttributes.frame.origin.y
            if (abs(itemOffset - verticalOffset) < abs(offsetAdjustment)) {
                offsetAdjustment = itemOffset - verticalOffset
            }
        }
        
        return CGPoint(x: proposedContentOffset.x, y: proposedContentOffset.y + offsetAdjustment)
    }
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributesArray  = super.layoutAttributesForElements(in: rect)
        
        attributesArray?.forEach({ (attributes) in
            var length: CGFloat = 0
            var contentOffset: CGFloat = 0
            var position: CGFloat = 0
            let collectionView = self.collectionView!
            
            if (self.scrollDirection == .horizontal) {
                length = attributes.size.width
                contentOffset = collectionView.contentOffset.x
                position = attributes.center.x - attributes.size.width / 2
            } else {
                length = attributes.size.height
                contentOffset = collectionView.contentOffset.y
                position = attributes.center.y - attributes.size.height / 2
            }
            
            if (position >= 0 && position <= contentOffset) {
                let differ: CGFloat = contentOffset - position
                let alphaFactor: CGFloat =  1 - differ / length
                attributes.alpha = alphaFactor
                attributes.transform3D = CATransform3DMakeTranslation(0, differ, 0)
            } else if (position - contentOffset > collectionView.frame.height - Layout.model.height - Layout.model.spacing
                && position - contentOffset <= collectionView.frame.height) {
                let differ: CGFloat = collectionView.frame.height - position + contentOffset
                let alphaFactor: CGFloat =  differ / length
                attributes.alpha = alphaFactor
                attributes.transform3D = CATransform3DMakeTranslation(0, differ - length, 0)
                attributes.zIndex = -1
            } else {
                attributes.alpha = 1
                attributes.transform = CGAffineTransform.identity
            }
        })
        
        return attributesArray
    }
    
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return true
    }
    

    【讨论】:

    • 什么是Layout.model.heightLayout.model.spacing
    • 这是一个常数值,因为我记得单元格的高度和间距
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-13
    相关资源
    最近更新 更多