首页 > 运维 > linux运维 > 正文

使用 UICollectionView 实现分页滑动效果

爱谁谁
发布: 2025-07-23 09:52:18
原创
637人浏览过

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

使用 UICollectionView 实现分页滑动效果

这个问题确实存在,因为 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 停止滚动时的偏移量。我们可以通过重写这个函数来实现自定义的分页滚动。重写这个函数的逻辑如下:

  1. 定义一个 CGPoint 来记录最新滚动的偏移坐标。
  2. 定义两个值,分别为 UICollectionView 可滚动的最大偏移量和最小偏移量(即 0)。
  3. 每次滚动停止时都会调用上述函数 func targetContentOffset(...),这个函数有一个参数 proposedContentOffset 记录了滚动的目标位移坐标。通过这个坐标和记录的上次滚动的坐标,可以判断出是向左滚动还是向右滚动。
  4. 如果两个坐标的水平方向相减的绝对值大于某个固定值(例如 item 宽度的八分之一),则可以判断发生了分页,然后通过 proposedContentOffset 位移坐标和 item 的宽度大小来计算出当前滚动的页码;如果小于那个固定值,则不发生分页。
  5. 最后记录最新的偏移坐标,然后返回 UICollectionView 停止滚动时的偏移量。

言语空洞,让我们看代码,实现如下:

火龙果写作
火龙果写作

用火龙果,轻松写作,通过校对、改写、扩展等功能实现高质量内容生产。

火龙果写作 106
查看详情 火龙果写作
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
    }
}
登录后复制

运行效果如下:

使用 UICollectionView 实现分页滑动效果

至此,本文结束。按照惯例,文章末尾会提供 demo 工程的地址。

以上就是使用 UICollectionView 实现分页滑动效果的详细内容,更多请关注php中文网其它相关文章!

相关标签:
最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号