使用 UICollectionView 实现分页滑动效果
发布时间 - 2025-07-23 00:00:00 点击率:次在上一篇博文中,我们展示了如何使用 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 停止滚动时的偏移量。我们可以通过重写这个函数来实现自定义的分页滚动。重写这个函数的逻辑如下:
- 定义一个 CGPoint 来记录最新滚动的偏移坐标。
- 定义两个值,分别为 UICollectionView 可滚动的最大偏移量和最小偏移量(即 0)。
- 每次滚动停止时都会调用上述函数 func targetContentOffset(...),这个函数有一个参数 proposedContentOffset 记录了滚动的目标位移坐标。通过这个坐标和记录的上次滚动的坐标,可以判断出是向左滚动还是向右滚动。
- 如果两个坐标的水平方向相减的绝对值大于某个固定值(例如 item 宽度的八分之一),则可以判断发生了分页,然后通过 proposedContentOffset 位移坐标和 item 的宽度大小来计算出当前滚动的页码;如果小于那个固定值,则不发
生分页。 - 最后记录最新的偏移坐标,然后返回 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 工程的地址。
# ios
# red
# bug
# 分页
# 偏移量
# 重写
# 有一个
# 自定义
# 设置为
# 返回值
# 决定了
# 让我们
# 这个问题
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
java获取注册ip实例
Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】
Laravel distinct去重查询_Laravel Eloquent去重方法
如何快速启动建站代理加盟业务?
如何快速生成橙子建站落地页链接?
如何用花生壳三步快速搭建专属网站?
如何用JavaScript实现文本编辑器_光标和选区怎么处理
,在苏州找工作,上哪个网站比较好?
Python文件操作最佳实践_稳定性说明【指导】
三星、SK海力士获美批准:可向中国出口芯片制造设备
HTML5空格和margin有啥区别_空格与外边距的使用场景【说明】
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
Mybatis 中的insertOrUpdate操作
Linux系统命令中tree命令详解
Laravel如何为API编写文档_Laravel API文档生成与维护方法
Laravel如何创建自定义Artisan命令?(代码示例)
EditPlus 正则表达式 实战(3)
如何快速辨别茅台真假?关键步骤解析
悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤
如何挑选高效建站主机与优质域名?
Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区
Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置
Laravel如何创建自定义中间件?(Middleware代码示例)
微信小程序 require机制详解及实例代码
如何快速登录WAP自助建站平台?
Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】
如何快速查询网址的建站时间与历史轨迹?
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
做企业网站制作流程,企业网站制作基本流程有哪些?
Laravel怎么解决跨域问题_Laravel配置CORS跨域访问
大型企业网站制作流程,做网站需要注册公司吗?
WEB开发之注册页面验证码倒计时代码的实现
深圳网站制作的公司有哪些,dido官方网站?
如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?
如何用AI一键生成爆款短视频文案?小红书AI文案写作指令【教程】
JS去除重复并统计数量的实现方法
jQuery 常见小例汇总
Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】
Laravel软删除怎么实现_Laravel Eloquent SoftDeletes功能使用教程
如何快速完成中国万网建站详细流程?
JS实现鼠标移上去显示图片或微信二维码
Laravel怎么发送邮件_Laravel Mail类SMTP配置教程
js代码实现下拉菜单【推荐】
浅谈Javascript中的Label语句
如何在IIS服务器上快速部署高效网站?
WordPress 子目录安装中正确处理脚本路径的完整指南
Laravel Octane如何提升性能_使用Laravel Octane加速你的应用
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
历史网站制作软件,华为如何找回被删除的网站?
php 三元运算符实例详细介绍


生分页。