当前位置: 首页 > news >正文

Swift手撸轮播效果

一、创建ScrollView

@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)}
}

二、处理手势

@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
}

三、注意事项

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.lryc.cn/news/341459.html

相关文章:

  • 数据分析——业务数据描述
  • 【哈希表】Leetcode 14. 最长公共前缀
  • (三)JVM实战——对象的内存布局与执行引擎详解
  • 微信视频号如何变现呢,视频号涨粉最快方法
  • 数智先锋 | 多场景数据治理案例,释放数据要素生产力
  • UE5 audio capture 回声问题 ||在安卓上有爆鸣声
  • 第 10 场蓝桥杯小白入门赛题解
  • 抖音视频评论区用户采集 根据视频链接批量获取用户信息
  • C++ 多态(一)
  • [Linux][网络][TCP][一][TCP基础][TCP报头]详细讲解
  • java-函数式编程-函数对象
  • 致远oa实时获取第三方自定义组件实现
  • 【Linux-点灯烧录-SD卡/USB烧写】
  • PostgreSQL自带的命令行工具06- pg_isready
  • 【请投票】嘉立创EDA中LED发光二极管是否应有统一的引脚定义?
  • LT6911UXB HDMI2.0 至四端口 MIPI DSI/CSI,带音频 龙迅方案
  • 网络培训议题@2
  • linux文本三剑客之sed
  • nginx封禁恶意IP
  • 「PHP系列」PHP MySQL 简介及运用
  • 深度学习论文: XFeat: Accelerated Features for Lightweight Image Matching
  • C++之Eigen库基本使用
  • 2024年 Java 面试八股文——SpringBoot篇
  • C/C++的指针、万能指针、常量指针和指针常量
  • 【讲解下如何解决一些常见的 Composer 错误】
  • qq空间:图片批量下载js脚本工具,javascript批量下载图片
  • 滑动验证码登陆测试编程示例
  • 爬取89ip代理、 爬取豆瓣电影
  • XBoot:基于Spring Boot 2.x的一站式前后端分离快速开发平台
  • 24年最新抖音、视频号0成本挂机,单号每天收益上百,可无限挂