在上一篇博文中,我们展示了如何使用 uicollectionview 实现卡片轮播效果。有网友反馈了一个问题:当 item 的宽度与屏幕宽度一致时,滚动效果正常,但当 item 宽度小于屏幕宽度时,会出现遮挡的 bug。如何解决这个问题呢?

这个问题确实存在,因为 UICollectionView 有一个分页属性 isPagingEnabled,当设置为 true 时,每次滚动的位移量等于屏幕宽度;当设置为 false 时(默认值),滚动没有分页效果。有人可能会问,UICollectionView 是否只能按照屏幕大小进行分页?答案当然是否定的。
要实现自定义的滚动分页,我们需要依赖 UICollectionViewFlowLayout。在 UICollectionViewFlowLayout 中,有一个可以重写的函数:
func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint // return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior
这个函数的返回值决定了 UICollectionView 停止滚动时的偏移量。我们可以通过重写这个函数来实现自定义的分页滚动。重写这个函数的逻辑如下:
言语空洞,让我们看代码,实现如下:
class RowStyleLayout: UICollectionViewFlowLayout {
private var lastOffset: CGPoint!
override init() {
super.init()
lastOffset = CGPoint.zero
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 初始化
override func prepare() {
super.prepare()
self.collectionView?.decelerationRate = .fast
}
// 这个方法的返回值,决定了 CollectionView 停止滚动时的偏移量
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
// 分页的 width
let pageSpace = self.stepSpace()
let offsetMax: CGFloat = self.collectionView!.contentSize.width - (pageSpace + self.sectionInset.right + self.minimumLineSpacing)
let offsetMin: CGFloat = 0
// 修改之前记录的位置,如果小于最小的contentsize或者最大的contentsize则重置值
if lastOffset.x < offsetMin {
lastOffset.x = offsetMin
} else if lastOffset.x > offsetMax {
lastOffset.x = offsetMax
}
// 目标位移点距离当前点距离的绝对值
let offsetForCurrentPointX: CGFloat = abs(proposedContentOffset.x - lastOffset.x)
let velocityX = velocity.x
// 判断当前滑动方向,向左 true, 向右 false
let direction: Bool = (proposedContentOffset.x - lastOffset.x) > 0
var newProposedContentOffset: CGPoint = CGPoint.zero
if (offsetForCurrentPointX > pageSpace/8.0) && (lastOffset.x >= offsetMin) && (lastOffset.x <= offsetMax) {
if direction {
newProposedContentOffset.x = ceil((proposedContentOffset.x - self.sectionInset.left) / pageSpace) * pageSpace + self.sectionInset.left
} else {
newProposedContentOffset.x = floor((proposedContentOffset.x - self.sectionInset.left) / pageSpace) * pageSpace + self.sectionInset.left
}
} else {
newProposedContentOffset.x = lastOffset.x
}
lastOffset = newProposedContentOffset
return newProposedContentOffset
}
func stepSpace() -> CGFloat {
return self.itemSize.width + self.minimumLineSpacing
}
}运行效果如下:

至此,本文结束。按照惯例,文章末尾会提供 demo 工程的地址。
以上就是使用 UICollectionView 实现分页滑动效果的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号