自定义UICollectionViewFlowLayout应用transform后顶部cell突然消失如何解决
问题原因
- 系统默认的
layoutAttributesForElements方法只会返回原始frame落在查询矩形内的cell属性。当顶部cell滚动到原始可见区域外时,super方法不会返回它的布局属性,你无法为其设置渐变动画参数,系统会直接回收该cell,导致突然消失。 - 现有代码未对alpha、scale做取值限制,当滚动距离过大时会出现负数,也会导致cell异常不可见。
修复后的代码
class EdgeZoomLayout: UICollectionViewFlowLayout { override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { guard let collectionView = collectionView else { return nil } // 扩大查询范围,覆盖顶部100pt的渐隐区域,确保渐变中的cell不会被漏掉 let extendedRect = rect.inset(by: UIEdgeInsets(top: 100, left: 0, bottom: 0, right: 0)) let rectAttributes = super.layoutAttributesForElements(in: extendedRect)!.map { $0.copy() as! UICollectionViewLayoutAttributes } let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.frame.size) for attributes in rectAttributes { let positionInFrameY = attributes.center.y - visibleRect.origin.y let cutoff = CGFloat(30) if positionInFrameY <= cutoff { let translation = cutoff - positionInFrameY // 限制alpha在0~1之间,避免出现负数 let alpha = max(0, min(1, 1 - (translation / 100))) // 限制最小缩放值,可根据需求调整下限 let scale = max(0.8, min(1, 1 - (translation / 1000))) attributes.alpha = alpha // 渐变中的cell设为更高层级,避免被下方cell遮挡 attributes.zIndex = 2 attributes.transform = CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: 0, y: translation) } else { attributes.alpha = 1 attributes.transform = .identity attributes.zIndex = 1 } } return rectAttributes } override init() { super.init() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { return true } override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext { let context = super.invalidationContext(forBoundsChange: newBounds) as! UICollectionViewFlowLayoutInvalidationContext context.invalidateFlowLayoutDelegateMetrics = newBounds.size != collectionView?.bounds.size return context } }
补充说明
你可以根据自己的效果需求调整两个参数:
- 扩大查询范围的top值:和你计算alpha时分母的100保持一致即可,确保alpha降到0之前的cell都能被查询到
- scale的最小下限:如果不需要限制最小缩放,可以把
max(0.8, ...)去掉,直接计算即可
内容的提问来源于stack exchange,提问作者aheze
相关产品推荐
相关产品推荐

