Swift手撸轮播效果

embedded/2024/10/18 2:36:23/

一、创建ScrollView

swift">@objcMembers class LSLottieAnimView: UIView, UIScrollViewDelegate {private var scrollView: UIScrollView = UIScrollView()func addScrollView() {scrollView.showsHorizontalScrollIndicator = falsescrollView.isPagingEnabled = true// 自定义framescrollView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)scrollView.delegate = self// 此处创建了三个子view的宽度scrollView.contentSize = CGSize(width: scrollView.frame.width * CGFloat(3), height: scrollView.frame.height)let u1 = UIView()u1.frame = scrollView.boundsu1.backgroundColor = .blacklet u2 = UIView()u2.frame = scrollView.boundsu2.backgroundColor = .greenlet u3 = UIView()u3.frame = scrollView.boundsu3.backgroundColor = .yellowscrollView.addSubview(u1)scrollView.addSubview(u2)scrollView.addSubview(u3)UIApplication.shared.keyWindow?.rootViewController?.view.addSubview(scrollView)// 添加拖拽手势识别器let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))scrollView.addGestureRecognizer(panGesture)}
}

二、处理手势

swift">@objc func handlePan(_ gesture: UIPanGestureRecognizer) {let scrollView = gesture.view as! UIScrollViewlet translation = gesture.translation(in: scrollView)// let count = scrollView.subviews.count - 1 - 1;// 禁止回弹if (scrollView.contentOffset.x <= 0 && translation.x > 0) || (Int(scrollView.frame.width) * count <= Int(scrollView.contentOffset.x) && translation.x < 0) {return}// 当setContentOffset的动画未完成时,此时isDecelerating为trueif scrollView.isDecelerating || !scrollView.isScrollEnabled {return}switch gesture.state {// case .began:// 如果开启轮播,则停止自动轮播// scrollView.layer.removeAllAnimations()case .changed:// 根据手势的偏移量进行滚动if scrollView.contentOffset.x - translation.x <= 0 {scrollView.contentOffset.x = 0} else if scrollView.contentOffset.x - translation.x >= scrollView.frame.width * CGFloat(count) {scrollView.contentOffset.x = scrollView.frame.width * CGFloat(count)} else {scrollView.contentOffset.x -= translation.x}case .ended, .cancelled, .failed:// 获取滚动视图当前的页索引let pageIndex = Int(scrollView.contentOffset.x / scrollView.frame.width)// 修改后的页面索引var willPageIndex = pageIndex// 根据手势的速度和偏移量来判断是否切换到上一页或下一页let velocity = gesture.velocity(in: scrollView)if velocity.x > 0 {// 向右滑动} else if velocity.x < 0 {// 向左滑动if pageIndex < count {willPageIndex = pageIndex + 1}} else {// 根据偏移量判断是否切换到上一页或下一页if translation.x < -scrollView.frame.width / 2 && pageIndex < count {willPageIndex = pageIndex + 1} else if translation.x > scrollView.frame.width / 2 && pageIndex > 0 {willPageIndex = pageIndex - 1}}// 只有修改后才需要调用setContentOffset,否则会出现scrollViewDidEndScrollingAnimation不调用的情况if (scrollView.contentOffset.x != CGFloat(willPageIndex) * scrollView.frame.width) {scrollView.setContentOffset(CGPoint(x: CGFloat(willPageIndex) * scrollView.frame.width, y: 0), animated: true)scrollView.isScrollEnabled = false}default:break}// 重置手势的偏移量gesture.setTranslation(.zero, in: scrollView)
}// MARK: UIScrollViewDelegate
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {scrollView.isScrollEnabled = true
}

三、注意事项

swift">1. 如果需要回弹,只需要修改如下代码即可
// 注释如下代码
if (scrollView.contentOffset.x <= 0 && translation.x > 0) || (Int(scrollView.frame.width) * count <= Int(scrollView.contentOffset.x) && translation.x < 0) {return
}// 修改成如下代码case .changed:
//            // 根据手势的偏移量进行滚动
//            if scrollView.contentOffset.x - translation.x <= 0 {
//                scrollView.contentOffset.x = 0
//            } else if scrollView.contentOffset.x - translation.x >= scrollView.frame.width * CGFloat(count) {
//                scrollView.contentOffset.x = scrollView.frame.width * CGFloat(count)
//            } else {scrollView.contentOffset.x -= translation.x
//            }2. 在调用setContentOffset且animated为true时,需要考虑将isScrollEnabled设置为false,等到动画完成后(scrollViewDidEndScrollingAnimation)将isScrollEnabled恢复到true,否则在动画期间仍然可以拖拽
3. 在调用setContentOffset时,如果值和之前相同,则不会触发scrollViewDidEndScrollingAnimation

http://www.ppmy.cn/embedded/27994.html

相关文章

【go零基础】go-zero从零基础学习到实战教程 - 2项目初始化

到项目初始化过程了&#xff0c;这边的项目设计完全按照作者自己的喜好来进行定义和设置的&#xff0c;所以各位完全可以按照自己的偏好自喜设置哈。 首先是创建一个工作文件夹哈。 别问为啥不直接quickstart&#xff0c;因为quickstart生成的api名字是greet&#xff0c;改起来…

Django后台项目开发实战七

为后台管理系统换风格 第七阶段 安装皮肤包 pip install django-grappelli 在 setting.py 注册 INSTALLED_APPS [grappelli,django.contrib.admin,django.contrib.auth,django.contrib.contenttypes,django.contrib.sessions,django.contrib.messages,django.contrib.stat…

蓝桥杯2022年第十三届决赛真题-最大数字

知识点&#xff1a; double -------(max)10的308次幂 long long ---------(max)10的18次幂 过 96% 的方法 贪心思想&#xff1a;根据数据范围&#xff0c;很容易想到应该用for遍历每一位&#xff0c;复杂度是O(1)。从前往后看每一位&#xff0c;比较通过到达9和通过-到达9的个…

图像处理的一些操作(2)

图像处理 9. 转换类型9.1转换成浮点数类型9.2转换成无符号字节类型 10.颜色空间转换10.1RGB转GRAY10.2RGB转HSV10.3RGB转LAB10.4HSV转RGB10.5LAB转RGB10.6 convert_colorspace函数进行颜色转换 11.标签化处理图像11.1导入模块11.2加载图片11.3RGB图像转灰度图像11.4遍历图像11.…

springcloud第4季 springcloud-alibaba之分布式事务seata

一 seata介绍 1.1 seata介绍 1.seata是一款解决分布式事务的解决方案&#xff0c;致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 二 seata的操作 2.1 seata操作 1.seata的安装 2.seata数据库导入脚本 3.seata的server配置安装

基于SSM的个人博客系统(五)

前面内容请移步 基于SSM的个人博客系统&#xff08;四&#xff09; 个人博客系统的设计与实现免费源码论文 个人博客系统的设计与实现毕业设计论文源码 第六章 系统测试 6.1 前台模块测试 浏览器的网址输入框中输入正确的地址既可以看到系统前台页面: 图5-1前台展示页面 …

JMeter性能压测脚本录制

第一步&#xff1a;电脑打开控制面板设置代理服务器 第二步&#xff1a;jmeter的测试计划添加一个HTTP&#xff08;S&#xff09;脚本记录器 在脚本记录器里配置好信息&#xff0c;然后保存为脚本文件&#xff08;.*表示限定&#xff09; 此方框内容为项目地址&#xff08;可改…

Istio介绍

1.什么是Istio Istio是一个开源的服务网格&#xff08;Service Mesh&#xff09;框架&#xff0c;它提供了一种简单的方式来为部署在Kubernetes等容器编排平台上的微服务应用添加网络功能。Istio的核心功能包括&#xff1a; 服务治理&#xff1a;Istio能够帮助管理服务之间的…