swift之图片轮播 、跑马灯

xiaoxiao2022-06-12  22

图片轮播的几种实现思路:https://www.jianshu.com/p/54a6ecea22e2

轮播框架:WRCycleScrollView------https://github.com/wangrui460/WRCycleScrollView

https://github.com/topics/sdcyclescrollview

 

==========轮播实现方式一用scrollview实现============

1.利用三个imageview

UIScrollView  ,有定时器自动轮播,无动画,有点击事件

/*轮播实现原理:scrollview上用三个imageview显示,每次滚动后重新计算出上一页、当前页、下一页需要显示的图片; 使用: import UIKit class LYBHomeVC: LYBBaseVC , CycleScrollViewDelegate { var images: [String] = ["lunboone.png", "lunbotwo.png", "lunbothree.png","lunbofour"] var cycleView: LYBCycleScrollView! override func viewDidLoad() { super.viewDidLoad() cycleView = LYBCycleScrollView(frame: CGRect.init(x: 0, y: 0, width: view.frame.width, height: 200)) cycleView.delegate = self cycleView.rollingEnable = true view.addSubview(cycleView) } /// 设置图片数量 func cycleImageCount() -> Int { return images.count } /// 设置显示的图片 func cycleImageView(_ imageView: UIImageView, index: Int) { imageView.image = UIImage(named: images[index]) } /// 点击图片,返回下标 func cycleImageViewClick(_ index: Int) { print(index) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } */ import UIKit /// 代理方法 @objc protocol CycleScrollViewDelegate: NSObjectProtocol { /// 有多少图片 func cycleImageCount() -> Int /// 图片和当前下标 func cycleImageView(_ imageView: UIImageView, index: Int) /// 点击图片下标 @objc optional func cycleImageViewClick(_ index: Int) } /// 轮播图 class LYBCycleScrollView: UIView, UIScrollViewDelegate { /// 图片数组,第一张和第三张是占位 private var imageViews = [UIImageView(), UIImageView(), UIImageView()] /// 滚动页面 private var scrollView: UIScrollView! /// 图片个数 private var imageCount: Int = 0 /// 计时器 private var timer: Timer? = nil /// 存储下标 private var index: Int = 0 /// 当前显示下标 public var currentIndex: Int { get { return index } set { index = min(newValue, imageCount) updateImage() } } /// 是否滚动 public var rollingEnable: Bool = false { willSet { newValue ? startTimer() : stopTimer() } } /// 滚动间隔 public var duration: TimeInterval = 3.0 /// 代理,观察属性 public weak var delegate: CycleScrollViewDelegate? { didSet { if let delegate = delegate { imageCount = delegate.cycleImageCount()//从代理方法返回图片的数量 scrollView.isScrollEnabled = imageCount > 1 print("imagecount\(imageCount)") } } } /// 初始化 override init(frame: CGRect) { super.init(frame: frame) scrollView = UIScrollView() scrollView.isPagingEnabled = true scrollView.bounces = false scrollView.showsHorizontalScrollIndicator = false scrollView.showsVerticalScrollIndicator = false scrollView.delegate = self addSubview(scrollView) //把UIImageview添加到scrollview上 for item in imageViews { scrollView.addSubview(item) } //添加点击的手势 addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap(_:)))) } /// 设置 override func layoutSubviews() { super.layoutSubviews() if (imageViews[0].frame == .zero) { let width = frame.width, height = frame.height scrollView.frame = CGRect(x: 0, y: 0, width: width, height: height) scrollView.contentSize = CGSize(width: width * 3, height: height) for (i, obj) in imageViews.enumerated() { obj.frame = CGRect(x: CGFloat(i) * width, y: 0, width: width, height: height) } currentIndex = index print("layoutSubviews\(index)") } } /// 点击 @objc private func tap(_ gesture: UITapGestureRecognizer) { delegate?.cycleImageViewClick?(currentIndex) } /// 更新图片 private func updateImage() { print("currentIndex\(currentIndex)") if (imageCount < 2) {//原始的是三个imageview,第一张和第三张是占位,这里显示的是第二个imageview delegate?.cycleImageView(imageViews[1], index: index) print("\(index)") } else { for (i, index) in [getLast(currentIndex), currentIndex, getNext(currentIndex)].enumerated() { delegate?.cycleImageView(imageViews[i], index: index) print("第\(index)") } } //这一句话设置显示是第二个imageview scrollView.contentOffset.x = frame.width } /// 开始计时器 private func startTimer() { if (imageCount < 2) { return } timer = Timer.scheduledTimer(timeInterval: duration, target: self, selector: #selector(rolling), userInfo: nil, repeats: true) RunLoop.current.add(timer!, forMode: RunLoop.Mode.common) } /// 暂停计时器 private func stopTimer() { if (imageCount < 2) { return } timer?.invalidate() timer = nil } /// 计时方法 @objc private func rolling() { scrollView.setContentOffset(CGPoint(x: frame.width * 2, y: 0), animated: true) } /// scrollView开始拖拽 func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { if rollingEnable { stopTimer() } } /// scrollView结束拖拽 func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { if rollingEnable { startTimer() } } /// scrollView滚动 func scrollViewDidScroll(_ scrollView: UIScrollView) { if scrollView.contentOffset.x <= 0 { //右滑 currentIndex = getLast(currentIndex) print("右滑\(currentIndex)") } else if scrollView.contentOffset.x >= 2 * scrollView.frame.width { //左滑 currentIndex = getNext(currentIndex) print("左滑\(currentIndex)") } /// 修复automaticallyAdjustsScrollViewInsets问题 if (scrollView.contentOffset.y != 0) { scrollView.contentOffset.y = 0 } } /// 获取下一页页码 private func getNext(_ current: Int) -> Int { let count = imageCount - 1 if (count < 1) { return 0 } return current + 1 > count ? 0 : current + 1 } /// 获取上一页页码 private func getLast(_ current: Int) -> Int { let count = imageCount - 1 if (count < 1) { return 0 } return current - 1 < 0 ? count : current - 1 } /// 如果有计时器存在,必须停止计时器才能释放 override func removeFromSuperview() { super.removeFromSuperview() stopTimer() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }

 

 

===========图片轮播方式二==================

数组首尾添加尾首的两个元素组成新数组,然后利用scrollview的contentoffset偏移。

UISCrollview, 定时器自动轮播,无动画,点击事件

/** 首页轮播view 思路:假如图片数组有三个元素,把最后一个元素加到第一个之前,吧第一个元素加到最后一个,总共就有了五 个元素,开始的时候设置偏移量默认显示第二张图片。当在第四个元素向右滑的时候,设置setcontentoffset 到第二张图(也就是原始数组的第一张图),当从第二张图(也就是原始数组的第一张图)想左滑动的时候,设置 setcontentoffset到第四张图(也就是原始数组的最后一张图) 使用: import UIKit class LYBHomeVC: LYBBaseVC{ override func viewDidLoad() { super.viewDidLoad() self.view.addSubview(lunbo) setlunboview() } lazy var lunbo:LYBHomelunboview={ let headerscroll = LYBHomelunboview.init(frame: CGRect(x: 0, y: 0, width:Int(WIDTH) , height:LUNBOHEIGHT)) return headerscroll }() func setlunboview(){ lunbo.urlStrOrimageName="imageName"//imageName表示,传递图片名数组,默认是“”,表示传递的是url字符串 lunbo.scrollImages=["lunboone","lunbotwo","lunbothree","lunbofour"]//相当于重写set方法,如果传的是url字符串,上面的urlStrOrimageNameURL不要设置。 // weak var weakSelf = self //解决循环引用,这个是和oc一个写法 lunbo.scrollClickBlock={ // [weak self]//解决循环引用,这个是针对闭包,要写在闭包的前面 (index) in //传过来的tag,是从2开始 print("\(index)") switch index { case 0:break case 1: break case 2: print("\(index)") break case 3: break default: break } return } } } */ import UIKit class LYBHomelunboview: LYBBaseView,UIScrollViewDelegate { //属性观察器,相当于重写属性的set方法didset方法中scrollImages是新值,oldValue是旧值(固定写法) var scrollImages:[String]!=["lunboone"]{ willSet(scrollImagess) { print("新的值\(String(describing: scrollImages))") } didSet { print("新的值 \(String(describing: scrollImages))") print("旧的值 \(String(describing: oldValue)) ") initviews()//有数据了创建轮播 } } let animatetime=3//动画的时间和定时器时间,两者一致,否则滚动起来不协调 var urlStrOrimageName:String?=""//根据图片名加载,还是根据url加载,不传默认是url var isDisplayIndicator:Bool=true//是否显示指示器 var headerScroll:UIScrollView? var pagectr:UIPageControl? var lastOffset:CGFloat=0//上一次的偏移量 var derectStr:String?//方向字符串 var index:Int=1//定时器滚动的页码 var imageviewArr:[UIImageView]?//轮播imagview的数组 //定义一个闭包,有参数没返回值 var scrollClickBlock:(Int)->()={ (Int)->()in return } override init(frame: CGRect) { super.init(frame: frame) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func initviews(){ headerScroll=UIScrollView.init(frame: CGRect(x: 0, y: 0, width:Int(WIDTH) , height:LUNBOHEIGHT)) headerScroll!.delegate=self headerScroll?.showsHorizontalScrollIndicator=false headerScroll!.contentSize=CGSize(width: WIDTH*CGFloat(images.count)+10, height: 0) addSubview(headerScroll!) for i in 1...images.count { let imageV:UIImageView=UIImageView.init(frame: CGRect(x:(i-1)*Int(WIDTH), y:0, width:Int(WIDTH) , height:LUNBOHEIGHT)) imageV.isUserInteractionEnabled=true if urlStrOrimageName=="imageName"{ /** 图片名字符串 */ imageV.image=UIImage.init(named: images[i-1]) }else{ /** url显示图片 */ do{ let imageData:Data=try Data.init(contentsOf: URL.init(string: images[i-1])!) imageV.image=UIImage.init(data: imageData) }catch{ } } imageV.tag=i headerScroll!.addSubview(imageV) //添加点击的手势 imageV.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap(_:)))) imageviewArr?.append(imageV) } headerScroll!.contentSize=CGSize(width: WIDTH*CGFloat(images.count)+10, height: 0) headerScroll?.setContentOffset(CGPoint.init(x: WIDTH, y: 0), animated: false)//设置起始的偏移量为第二张图 lastOffset=headerScroll!.contentOffset.x//上一次的偏移量 headerScroll?.isPagingEnabled=true//分页 /** pageCcontrol */ pagectr=UIPageControl.init(frame: CGRect.init(x: 50, y: LUNBOHEIGHT-30, width: Int(WIDTH-100), height: 30)) pagectr?.numberOfPages=images.count-2;//第一张和最后一张不显示 pagectr?.pageIndicatorTintColor=UIColor.gray pagectr?.defersCurrentPageDisplay=false //取消延迟显示,默认是延迟显示小点 pagectr?.currentPageIndicatorTintColor=UIColor.red pagectr?.currentPage=0 if isDisplayIndicator{//控制指示器显示 self.addSubview(pagectr!) } self.startTimer()//定时器 } /// 点击 @objc private func tap(_ gesture: UITapGestureRecognizer) { //tag是从102开始, let imageviewTag=gesture.view!.tag-2//转化成从0开始 self.scrollClickBlock(imageviewTag) } //正在滚动,判断是左移还是右移 func scrollViewDidScroll(_ scrollView: UIScrollView) { print("滚动") //和上一次的偏移量做比较,判断滑动的方向 if scrollView.contentOffset.x > lastOffset{ derectStr="left" }else{ derectStr="right" } } //停止拖动--在didendDrag后面执行 func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { //当前的index index=Int(scrollView.contentOffset.x/WIDTH)//获取当前的偏移量 self.commonscroll() lastOffset=(headerScroll?.contentOffset.x)! print("开始定时器") self.startTimer()//定时器 } //刚开始拖拽 func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { print("停止计时器") stopTimer() } //手动拖拽 func commonscroll(){ if derectStr=="left"{//headerScroll!.contentOffset.x越来越大 if Int(index)==images.count-1 || Int(headerScroll!.contentOffset.x)>(images.count-1) * Int(WIDTH){ headerScroll?.setContentOffset(CGPoint.init(x: WIDTH, y: 0), animated: false)//偏移到第二张图片 pagectr?.currentPage=0//偏移到第二张图片 }else { headerScroll?.setContentOffset(CGPoint.init(x: index*Int(WIDTH), y: 0), animated: false)//带动画 } }else if derectStr=="right"{ if Int(index)==0 || Int(headerScroll!.contentOffset.x)<0{ headerScroll?.setContentOffset(CGPoint.init(x: (images.count-2)*Int(WIDTH), y: 0), animated: false)//偏移到倒数第二张图片 pagectr?.currentPage=images.count-2-1 //偏移到倒数第二张图片 }else{ headerScroll?.setContentOffset(CGPoint.init(x: index*Int(WIDTH), y: 0), animated: false)//带动画 } } if Int(index)==0 { } else if Int(index)==images.count-1{ }else { pagectr?.currentPage = Int((headerScroll?.contentOffset.x)!/WIDTH)-1 } } var timer : Timer? // .开始计时 func startTimer() { timer = Timer.scheduledTimer(timeInterval: TimeInterval(animatetime), target: self, selector: #selector(autoScroll), userInfo: nil, repeats: true) //调用fire()会立即启动计时器 // timer!.fire() RunLoop.current.add(timer!, forMode: RunLoop.Mode.common) } // .停止计时器 func stopTimer() { if timer != nil { timer!.invalidate() //销毁timer timer = nil } } // 定时操作 @objc func autoScroll() { print("dingshiqi") headerScroll!.setContentOffset(CGPoint.init(x: self.index * Int(WIDTH), y: 0), animated: false) // 把本次的偏移量计作为上一次的偏移 lastOffset=headerScroll!.contentOffset.x index=Int(headerScroll!.contentOffset.x/WIDTH)//当前页码 //定时器是向左滑动的 if Int(index)==images.count-1 { headerScroll?.setContentOffset(CGPoint.init(x: WIDTH, y: 0), animated: false)//偏移到第二张图片 pagectr?.currentPage=0//偏移到第二张图片,第一张图不显示指示器 lastOffset=(headerScroll?.contentOffset.x)! index=Int(headerScroll!.contentOffset.x/WIDTH) } if Int(index)==0 { } else if Int(index)==images.count-1{ }else { headerScroll!.setContentOffset(CGPoint.init(x: index * Int(WIDTH), y: 0), animated: true) pagectr?.currentPage = Int((headerScroll?.contentOffset.x)!/WIDTH)-1 } index+=1//swift中不支持++,-- } //懒加载---用到的时候才开始加载,scrollImages在调用的页面设置图片数组 lazy var images:[String]={ var newimages:[String]=scrollImages ?? ["lunboone"] newimages.insert(scrollImages![((scrollImages?.count)!-1)], at:0)//吧scrollImages的第一个元素插入到最后一个位置,组成新数组 newimages.append(scrollImages![0])//scrollImages的第一个元素插到最后一个位置 print("数组\(newimages)") return newimages }() //暂时没使用 //定时器执行的时候自带的动画不执行,这里自己定义一个动画加上 func layerTransition(direction:CATransitionSubtype,type:CATransitionType,timingFunc:CAMediaTimingFunctionName, duration: CGFloat, layer: CALayer) { let key = "transition"// if layer.animation(forKey: key) != nil { layer.removeAnimation(forKey: key) } let transition = CATransition() /// 动画时长 transition.duration = CFTimeInterval(duration) /// 动画类型 transition.type = CATransitionType(rawValue: type.rawValue) /// 动画方向 transition.subtype = CATransitionSubtype(rawValue:direction.rawValue) /// 缓动函数 transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName(rawValue:timingFunc.rawValue)) /// 完成动画删除 transition.isRemovedOnCompletion = true layer.add(transition, forKey: key)//key可以传nil } }

=========图片轮播方式二用collectionview实现========

首位添加cell的方式,

UICollectionView ,无定时器自动轮播,有动画

import UIKit let kScreenWidth = UIScreen.main.bounds.width class LYBCollectionveiwlunboview: UIView { override init(frame: CGRect) { super.init(frame: frame) setupController() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } lazy var collectionView: UICollectionView = { let flowLayout = UICollectionViewFlowLayout.init() flowLayout.minimumLineSpacing = 0 flowLayout.minimumInteritemSpacing = 0 flowLayout.scrollDirection = .horizontal flowLayout.itemSize = CGSize(width: kScreenWidth, height: 200) let collectionView = UICollectionView.init(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 200), collectionViewLayout: flowLayout) collectionView.isPagingEnabled = true collectionView.showsHorizontalScrollIndicator = false collectionView.backgroundColor = UIColor.white collectionView.delegate = self collectionView.dataSource = self self.addSubview(collectionView) return collectionView }() lazy var pageControl: UIPageControl = { let pageControl = UIPageControl(frame: CGRect(x: 0, y: 150, width: kScreenWidth, height: 50)) pageControl.numberOfPages = self.imageNameList.count pageControl.currentPage = 0 pageControl.tintColor = UIColor.black pageControl.pageIndicatorTintColor = UIColor.gray; return pageControl; }() lazy var imageNameList: [String] = { let imageArr = ["lunboone", "lunbotwo", "lunbothree"] return imageArr }() func setupController() { /// 设置数据 collectionView.register(ImageCollectionViewCell.self, forCellWithReuseIdentifier: "ImageCollectionViewCell") collectionView.scrollToItem(at: IndexPath(row: 1, section: 0), at: .left, animated: true) self.addSubview(pageControl) } var timer:Timer? func setPagectrl(){ if (collectionView.contentOffset.x == 0) { self.pageControl.currentPage = self.imageNameList.count /// 当UIScrollView滑动到最后一位停止时,将UIScrollView的偏移位置改变到第二个cell的位置 } else if (collectionView.contentOffset.x == CGFloat(self.imageNameList.count + 1) * kScreenWidth) { self.pageControl.currentPage = 0 } else { self.pageControl.currentPage = Int(collectionView.contentOffset.x / kScreenWidth) - 1 } } } extension LYBCollectionveiwlunboview: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { if (imageNameList.count == 0) { return 0 } return imageNameList.count + 2 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as! ImageCollectionViewCell /// 给图片赋值(在首尾分别添加两张图片)第一个cell显示最后一张图片 if (indexPath.row == 0) { cell.imageName = imageNameList.last } else if (indexPath.row == self.imageNameList.count + 1) { //最后一个cell显示第一张图片 cell.imageName = imageNameList.first } else { cell.imageName = imageNameList[indexPath.row - 1] } return cell } } extension LYBCollectionveiwlunboview: UICollectionViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { /// 当UIScrollView滑动到第一位停止时,将UIScrollView的偏移位置改变到倒数第二个cell的位置 if (scrollView.contentOffset.x == 0) { scrollView.contentOffset = CGPoint(x: CGFloat(self.imageNameList.count) * kScreenWidth,y: 0) self.pageControl.currentPage = self.imageNameList.count print("\(self.imageNameList.count)") print("\(self.pageControl.currentPage)") /// 当UIScrollView滑动到最后一位停止时,将UIScrollView的偏移位置改变到第二个cell的位置 } else if (scrollView.contentOffset.x == CGFloat(self.imageNameList.count + 1) * kScreenWidth) { scrollView.contentOffset = CGPoint(x: kScreenWidth,y: 0) self.pageControl.currentPage = 0 } else { self.pageControl.currentPage = Int(scrollView.contentOffset.x / kScreenWidth) - 1 print("\(self.pageControl.currentPage)") } } } //cell import UIKit class ImageCollectionViewCell: UICollectionViewCell { /// 显示的图片 let imageView = UIImageView() var imageName: String? = "" { didSet { if let name = imageName { imageView.image = UIImage(named: name) } } } override init(frame: CGRect) { super.init(frame: frame) setupCell(); } /// 初始化视图 func setupCell() { imageView.frame = self.bounds contentView.addSubview(imageView) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }

 

 

=======图片轮播三=====一般的功能可以用,手动拖拽后定时器运行有瑕疵,有待改进,

//这里是定时器销毁的做法,可以延迟执行,有瑕疵,但是和其他几种方式比,内存占用稍微低一些。

UICollectionview,定时器自动无限轮播,有动画

//无线轮播要关注的几个问题:滚动到边界的时候怎么处理;自动轮播定时器逻辑怎么设置; //这里是定时器销毁的做法,可以延迟执行,有瑕疵,但是和其他几种方式比,内存占用稍微低一些 /* 使用: let v=LYBLuncollectionview.init(frame: CGRect.init(x: 0, y: 0, width: WIDTH, height: 200)) v.imageList=["lunboone","lunbotwo","lunbothree","lunbofour"] v.index=4 self.view.addSubview(v) */ import UIKit let lunbocellidentifier="LYBLunboCollectionViewCell" class LYBLuncollectionview: UIView,UICollectionViewDelegate,UICollectionViewDataSource { func numberOfSections(in collectionView: UICollectionView) -> Int { return 3 } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return imageArr.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell:LYBLunboCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: lunbocellidentifier, for: indexPath) as! LYBLunboCollectionViewCell cell.backgroundColor=UIColor.red cell.imagestr=imageArr[indexPath.item] return cell } override init(frame: CGRect) { super.init(frame: frame) self.isUserInteractionEnabled=true addSubview(collectionv) //先默认滚动到第二组第一个 collectionv.scrollToItem(at: IndexPath.init(item: 0, section: 1) as IndexPath, at: UICollectionView.ScrollPosition.right, animated: false) addSubview(pagectr) setTimer() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } var imageArr:[String]=["lunboone"] var index:Int=4 //定时器执行滚动的索引,默认是第二组第一个的索引 var imageList:[String]=[]{ didSet{ print("数组\(imageList)") imageArr=imageList index=imageList.count pagectr.numberOfPages=imageList.count; collectionv.reloadData() collectionv.scrollToItem(at: IndexPath.init(item: 0, section: 1) as IndexPath, at: UICollectionView.ScrollPosition.right, animated: false) } } var section:Int=0//当前的组 var row:Int=0//当前的cell var timer:Timer? var intervtim:Double = 4 //定时器周期 var delaytime:Double=4//延迟执行定时器的时间 var isDrag:Bool=false//是否拖拽 var lastOffset:CGFloat=0//上一次的偏移量 var derectStr:String="right"//方向字符串---暂时没有用到 var firstsec:TimeInterval=0;//初始时间--为了控制手动拖拽后多久启动定时器 var secsec:TimeInterval=0;//现在的时间 func setTimer(){ timer = Timer.scheduledTimer(timeInterval:TimeInterval(intervtim), target: self, selector: #selector(timerrun), userInfo: nil, repeats: true) //common里面包含defaultmode和trackongmode,拖动scrollview的时候就变成tracking,不拖动了就是defultmode,trackongmode的优先级高于default,使用common,两种模式可以自由切换, RunLoop.main.add(timer!, forMode: RunLoop.Mode.common) // timer?.fire()// 立即执行定时器 } @objc func timerrun(){ print("第\(index)个cell") //1套方案,不停的创建定时器,销毁定时器,这个不太好,但是内存也不会增长 collectionv.setContentOffset(CGPoint.init(x: Int(WIDTH)*index, y: 0), animated: true) lastOffset=collectionv.contentOffset.x//记录上一次的偏移,用来判断滚动方向 pagectr.currentPage=index%imageArr.count //到达第三组第一个,取消定时器,静默就滚动到第二组第一个(千万不要带动画),索引重置 if index==imageArr.count*2{ timerInvalide() DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+TimeInterval(delaytime)) { [weak self] in self!.collectionv.scrollToItem(at: IndexPath.init(item: 0, section: 1) as IndexPath, at: UICollectionView.ScrollPosition.right, animated: false) self!.index=self!.imageArr.count//把索引重置到第二组第一个 self!.index+=1//本身就在第二组第一个,所以重启定时器的时候要滚动到下一个(为了能连续滚动),所以这里要+1 if self!.isDrag==false{//拖拽的时候定时器停止,找个合适的时间吧这个状态重置为false,才可以重新开启定时器 self!.setTimer()//重新创建定时器 } } }else{ timerInvalide() DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+TimeInterval(delaytime)) { [weak self] in if self!.isDrag==false{ self!.setTimer()//重新创建定时器 } } index+=1 } } //停止定时器 func timerInvalide(){ if timer != nil{ timer?.invalidate() timer=nil } } lazy var collectionv:UICollectionView={ let flowLayout = UICollectionViewFlowLayout.init() flowLayout.itemSize=CGSize.init(width: WIDTH, height: 200) flowLayout.minimumLineSpacing=0 flowLayout.minimumInteritemSpacing=0 flowLayout.scrollDirection = .horizontal var collec:UICollectionView? collec = UICollectionView.init(frame: CGRect.init(x: 0, y: 0, width: WIDTH, height: 200), collectionViewLayout: flowLayout) collec?.showsHorizontalScrollIndicator=false collec?.showsVerticalScrollIndicator=false collec?.backgroundColor=UIColor.white collec?.isPagingEnabled=true collec?.delegate=self collec?.dataSource=self collec?.isScrollEnabled=true collec?.register(LYBLunboCollectionViewCell.classForCoder(), forCellWithReuseIdentifier: lunbocellidentifier) return collec! }() lazy var pagectr:UIPageControl={ let pagectr:UIPageControl! pagectr=UIPageControl.init(frame: CGRect.init(x: 50, y: 180-30, width: Int(WIDTH-100), height: 30)) pagectr?.numberOfPages=3 pagectr?.pageIndicatorTintColor=UIColor.gray pagectr?.currentPageIndicatorTintColor=UIColor.red pagectr.hidesForSinglePage=true pagectr?.currentPage=0 return pagectr }() } extension LYBLuncollectionview{ //正在滚动,判断是左移还是右移 func scrollViewDidScroll(_ scrollView: UIScrollView) { //和上一次的偏移量做比较,判断滑动的方向 if scrollView.contentOffset.x > lastOffset{ derectStr="left" }else{ derectStr="right" } } //获取当前的组合cell func getSectionAndcell(){ // 将collectionView在控制器view的中心点转化成collectionView上的坐标 let pInView:CGPoint=self.convert(collectionv.center, to: collectionv) // 获取这一点的indexPath let indexpath = collectionv.indexPathForItem(at: pInView) section=indexpath!.section row=indexpath!.item } //手指在屏幕上开始拖拽 func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { timerInvalide() isDrag=true//标记为拖拽就不会创建定时器 print("定时器停止") firstsec = NSDate().timeIntervalSince1970//当前时间 lastOffset=collectionv.contentOffset.x //吧当前偏移量记录下来,作为上一次的偏移,用来判断滚动方向 //开始拖拽的时候就默认滚动到第二组 //第一组滚动到第二组 if lastOffset<CGFloat(imageArr.count)*WIDTH{ collectionv.setContentOffset(CGPoint.init(x: lastOffset+CGFloat(imageArr.count)*WIDTH, y: 0), animated: false) } //第三组滚动到第二组 if(lastOffset>CGFloat(imageArr.count)*WIDTH*2){ collectionv.setContentOffset(CGPoint.init(x: lastOffset-CGFloat(imageArr.count)*WIDTH, y: 0), animated: false) } } //停止拖拽,手指离开了屏幕,如果当前cell一半已经离开屏幕,就朝着多的方向滚动,直到整个cell滚动出屏幕 func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { lastOffset=collectionv.contentOffset.x //吧当前偏移量记录下来,作为上一次的偏移,用来判断滚动方向 let ishalf=lastOffset/WIDTH-floor(lastOffset/WIDTH) if ishalf>0.5{ if derectStr=="right"{ if section==0{ collectionv.setContentOffset(CGPoint.init(x: (floor(lastOffset/WIDTH)+1)*WIDTH+CGFloat(imageArr.count)*WIDTH, y: 0), animated: false) } if(section==2){ collectionv.setContentOffset(CGPoint.init(x: (floor(lastOffset/WIDTH)-1)*WIDTH-CGFloat(imageArr.count)*WIDTH, y: 0), animated: false) } }else { } } } //手动拖拽,手指离开了屏幕,滚动的cell停止加速度,减速完成(滚动停止) func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { /*获取当前的cell的Indexpath,这种方法获取Indexpath,会导致cell的位置不准确, 即使我的cell大小等于collectionView的大小,在[collectionView indexPathsForVisibleItems]方法得到的数组数据也有可能大于一个,并且顺序还不一定,导致我也不能通过firstObject或者lastObject来获取我想要的值 */ // let indexpath = collectionv.indexPathsForVisibleItems.first //获取section和row getSectionAndcell() print("row----\(String(describing: row))") //如果在第一组和第三组就默认滚动到第二组相应的cell if section==0||section==2{ if derectStr=="right"{ collectionv.scrollToItem(at: IndexPath.init(item:row, section: 1), at: UICollectionView.ScrollPosition.right, animated: false) }else { collectionv.scrollToItem(at: IndexPath.init(item:row, section: 1), at: UICollectionView.ScrollPosition.left, animated: false) } section=1 } index=imageArr.count+row//定时器执行滚动的索引 print("\(index)---组\(section)-\(String(describing: row))---\(Int(collectionv.contentOffset.x/WIDTH))") pagectr.currentPage=index%imageArr.count lastOffset=collectionv.contentOffset.x //记录上一次的偏移,用来判断滚动方向 isDrag=false secsec = NSDate().timeIntervalSince1970//当前时间,距离1970年的时间 print("相差的时间\(secsec-firstsec)") // 这个是开始拖拽到松开后的时间差,如果已经大于定时器延时的时间,就要重新开启定时器 if secsec-firstsec>delaytime{ timerrun() } } //停止滚动,自动滚动才执行,手势拖拽后停下来,这个方法不会执行 func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { print("停止滚动") getSectionAndcell() //index是在第七个cell停止下来的时候,就已经变成第八个cell的索引 if index==imageArr.count*2{//如果在第三组,默认滚动到第一组,上面的定时器正好可以加上动画 collectionv.scrollToItem(at: IndexPath.init(item: row, section: 0) as IndexPath, at: UICollectionView.ScrollPosition.right, animated: false) } } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { print("点击\(indexPath.item)") } } ****cell****** import UIKit class LYBLunboCollectionViewCell: UICollectionViewCell { var imageV:UIImageView! var imagestr:String="center"{ willSet(newvalue){ // print("new\(newvalue)") imageV.image=UIImage.init(named: newvalue) } didSet(oldvalue){ // print("old\(oldvalue)") // print("imagestr\(imagestr)") } } override init(frame: CGRect) { super.init(frame: frame) createCell() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func createCell(){ self.backgroundColor=UIColor.red imageV = UIImageView.init(frame:CGRect.init(x: 0, y: 0, width: WIDTH, height: self.frame.size.height)) imageV.image=UIImage.init(named: "center") imageV.isUserInteractionEnabled=true self.addSubview(imageV) } }

 

=========图片轮播四==========

推荐github下载地址:https://github.com/lambogoal/swiftImageScroll

码云下载地址:https://gitee.com/liyubao160/swiftlunbo.git

利用collectionview的组,创建三个组显示一样的图片,当处于第一图位置向前滚动或者处于最后一张图向后滚动时,就显示中间一组相应的图片。

UICollectionview,定时器自动无限轮播,有动画

/*UICollectionview,定时器自动无限轮播,有动画 let v=LYBLunboWithTimertwo.init(frame: CGRect.init(x: 0, y: 100, width: WIDTH, height: 200)) v.imageList=["lunboone","lunbotwo","lunbothree","lunbofour"] v.didselectBlock={ index in print("当前第\(index)") } self.view.addSubview(v) */ import UIKit let lunbocellidentifier="LYBLunboCollectionViewCell" class LYBLunboWithTimertwo: UIView,UICollectionViewDelegate,UICollectionViewDataSource{ func numberOfSections(in collectionView: UICollectionView) -> Int { return 3 } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return imageArr.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell:LYBLunbowithtimerCollectionviewcell = collectionView.dequeueReusableCell(withReuseIdentifier: lunbocellidentifier, for: indexPath) as! LYBLunbowithtimerCollectionviewcell cell.backgroundColor=UIColor.red cell.imagestr=imageArr[indexPath.item] return cell } override init(frame: CGRect) { super.init(frame: frame) self.isUserInteractionEnabled=true addSubview(collectionv) //先默认滚动到第二组第一个 collectionv.scrollToItem(at: IndexPath.init(item: 0, section: 1) as IndexPath, at: UICollectionView.ScrollPosition.right, animated: false) addSubview(pagectr) setTimer() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } //选中cell后的回调 var didselectBlock:(Int)->()={ index->Void in } var imageArr:[String]=["lunboone"] var index:Int=4 //定时器执行滚动的索引,默认是第二组第一个的索引 var imageList:[String]=[]{ didSet{ print("数组\(imageList)") imageArr=imageList index=imageList.count pagectr.numberOfPages=imageList.count; collectionv.reloadData() collectionv.scrollToItem(at: IndexPath.init(item: 0, section: 1) as IndexPath, at: UICollectionView.ScrollPosition.right, animated: false) } } var section:Int=0//当前的组 var row:Int=0//当前的cell var timer:Timer? var intervtim:Double = 4 //定时器周期 var delaytime:Double=4//延迟执行定时器的时间 var isDrag:Bool=false//是否拖拽 var lastOffset:CGFloat=0//上一次的偏移量 var derectStr:String="right"//方向字符串---暂时没有用到 func setTimer(){ timer = Timer.scheduledTimer(timeInterval:TimeInterval(intervtim), target: self, selector: #selector(timerrun), userInfo: nil, repeats: true) //common里面包含defaultmode和trackongmode,拖动scrollview的时候就变成tracking,不拖动了就是defultmode,trackongmode的优先级高于default,使用common,两种模式可以自由切换, RunLoop.main.add(timer!, forMode: RunLoop.Mode.common) // timer?.fire()// 立即执行定时器 } @objc func timerrun(){ print("第\(index)个cell") collectionv.setContentOffset(CGPoint.init(x: Int(WIDTH)*index, y: 0), animated: true) lastOffset=collectionv.contentOffset.x//记录上一次的偏移,用来判断滚动方向 pagectr.currentPage=index%imageArr.count //到达第三组第一个,取消定时器,静默就滚动到第二组第一个(千万不要带动画),索引重置 if index==imageArr.count*2{ collectionv.scrollToItem(at: IndexPath.init(item: 0, section: 1) as IndexPath, at: UICollectionView.ScrollPosition.right, animated: true) index=imageArr.count//把索引重置到第二组第一个 index+=1//本身就在第二组第一个,所以重启定时器的时候要滚动到下一个(为了能连续滚动),所以这里要+1 }else{ index+=1 } } //停止定时器 func timerInvalide(){ if timer != nil{ timer?.invalidate() timer=nil } } lazy var collectionv:UICollectionView={ let flowLayout = UICollectionViewFlowLayout.init() flowLayout.itemSize=CGSize.init(width: WIDTH, height: 200) flowLayout.minimumLineSpacing=0 flowLayout.minimumInteritemSpacing=0 flowLayout.scrollDirection = .horizontal var collec:UICollectionView? collec = UICollectionView.init(frame: CGRect.init(x: 0, y: 0, width: WIDTH, height: 200), collectionViewLayout: flowLayout) collec?.showsHorizontalScrollIndicator=false collec?.showsVerticalScrollIndicator=false collec?.backgroundColor=UIColor.white collec?.isPagingEnabled=true collec?.delegate=self collec?.dataSource=self collec?.isScrollEnabled=true collec?.register(LYBLunbowithtimerCollectionviewcell.classForCoder(), forCellWithReuseIdentifier: lunbocellidentifier) return collec! }() lazy var pagectr:UIPageControl={ let pagectr:UIPageControl! pagectr=UIPageControl.init(frame: CGRect.init(x: 50, y: 180-30, width: Int(WIDTH-100), height: 30)) pagectr?.numberOfPages=3 pagectr?.pageIndicatorTintColor=UIColor.gray pagectr?.currentPageIndicatorTintColor=UIColor.red pagectr.hidesForSinglePage=true pagectr?.currentPage=0 return pagectr }() } extension LYBLunboWithTimertwo{ //正在滚动,判断是左移还是右移 func scrollViewDidScroll(_ scrollView: UIScrollView) { //和上一次的偏移量做比较,判断滑动的方向,向左滑动scrollView.contentOffset.x越来越大 if scrollView.contentOffset.x > lastOffset{ derectStr="left" }else{ derectStr="right" } } //获取当前的组合cell func getSectionAndcell(){ // 将collectionView在控制器view的中心点转化成collectionView上的坐标 let pInView:CGPoint=self.convert(collectionv.center, to: collectionv) // 获取这一点的indexPath let indexpath = collectionv.indexPathForItem(at: pInView) section=indexpath!.section row=indexpath!.item } //手指在屏幕上开始拖拽 func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { //定时器暂停 timer?.fireDate = .distantFuture print("定时器暂停") } //停止拖拽,手指离开了屏幕,如果当前cell一半已经离开屏幕,就朝着多的方向滚动,直到整个cell滚动出屏幕 func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { } //手动拖拽,手指离开了屏幕,滚动的cell停止加速度,减速完成(滚动停止) func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { //获取section和row getSectionAndcell() print("row----\(String(describing: row))") //如果在第一组和第三组就默认滚动到第二组相应的cell if section==0||section==2{ if derectStr=="right"{ collectionv.scrollToItem(at: IndexPath.init(item:row, section: 1), at: UICollectionView.ScrollPosition.right, animated: false) }else { collectionv.scrollToItem(at: IndexPath.init(item:row, section: 1), at: UICollectionView.ScrollPosition.left, animated: false) } section=1 } index=imageArr.count+row//定时器执行滚动的索引 print("\(index)---组\(section)-\(String(describing: row))---\(Int(collectionv.contentOffset.x/WIDTH))") pagectr.currentPage=index%imageArr.count lastOffset=collectionv.contentOffset.x //记录上一次的偏移,用来判断滚动方向 //重新开启定时器 timer?.fireDate = .distantPast print("\(String(describing: timer))") } //停止滚动,自动滚动才执行,手势拖拽后停下来,这个方法不会执行 func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { print("停止滚动") //获取section和row getSectionAndcell() //index是在第七个cell停止下来的时候,就已经变成第八个cell的索引 if index==imageArr.count*2{//如果在第三组,默认滚动到第一组,上面的定时器正好可以加上动画 collectionv.scrollToItem(at: IndexPath.init(item: row, section: 0) as IndexPath, at: UICollectionView.ScrollPosition.right, animated: false) } } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { print("点击\(indexPath.item)") didselectBlock(indexPath.item) } } ******cell******* import UIKit class LYBLunbowithtimerCollectionviewcell: UICollectionViewCell { var imageV:UIImageView! var imagestr:String="center"{ willSet(newvalue){ //图片url if newvalue.range(of: "http://") != nil || newvalue.range(of: "https://") != nil{ //这里用的Data的方式显示图片,也可以使用图片下载框架Kingfisher let imageData:Data=try! Data.init(contentsOf: URL.init(string: newvalue)!) imageV.image=UIImage.init(data: imageData) }else{ //图片名 imageV.image=UIImage.init(named: newvalue) } } didSet(oldvalue){ // print("old\(oldvalue)") // print("imagestr\(imagestr)") } } override init(frame: CGRect) { super.init(frame: frame) createCell() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func createCell(){ self.backgroundColor=UIColor.red imageV = UIImageView.init(frame:CGRect.init(x: 0, y: 0, width: WIDTH, height: self.frame.size.height)) imageV.image=UIImage.init(named: "center") imageV.isUserInteractionEnabled=true self.addSubview(imageV) } }

 

================跑马灯=====================

跑马灯:https://github.com/pujiaxin33/JXMarqueeView

简易跑马灯:https://www.jianshu.com/p/a83a2152c8f1

/** 消息跑马灯,支持单张图片跑马灯,文字跑马灯 infoScroll.scrollImage="我是中国人,我是中国呢过是的撒发生大范德萨范德萨范德萨发是撒范德萨范德萨范德萨"//这个一定要先赋值 infoScroll.lblstrOrimageName="lblstr"//lblstr是label文字滚动,imageName表示是图片,必须赋值 infoScroll.sizefont=20//显示的字体大小 // infoScroll.scrollDerect=false//滚动方向,true代表水平(默认的) infoScroll.infoMarqueeClickBlock={ // [weak self]//解决循环引用 (index)in return } headerV.addSubview(infoScroll) */ import UIKit class LYBInfoScrollView: LYBBaseView ,UIScrollViewDelegate{ //属性观察器,相当于重写属性的set方法didset方法中scrollImages是新值,oldValue是旧值(固定写法) var scrollImage:String!="bankBlue"{ willSet(scrollImage) { print("新的值\(String(describing: scrollImage))") } didSet { print("新的值 \(String(describing: scrollImage))") print("旧的值 \(String(describing: oldValue)) ") // initviews()//有数据了创建轮播 } } //懒加载---用到的时候才开始加载 lazy var imageOrlblStr:String={ var newimage:String=scrollImage ?? "bankBlue" return newimage }() var lblstrOrimageName:String?{ willSet(lblstrOrimageName) { } didSet { // initviews()//有数据了创建轮播 } }//显示文字或者图片,imageNmae表示显示图片 var headerScroll:UIScrollView? var index:CGFloat=0.0//偏移量的默认值 var scrollDerect:Bool=true{ willSet(lblstrOrimageName) { } didSet { initviews()//有数据了创建轮播 }//true横向,false纵向 } var scrollClockwise:Bool=true{ willSet(lblstrOrimageName) { } didSet { // initviews()//有数据了创建轮播 }// true正向,false反向 } var sizefont:CGFloat=15{ didSet { initviews()//有数据了创建轮播 } } var realwidth:CGFloat=WIDTH//真实的数据长度 var realHeight:CGFloat=HEIGHT//真实的数据高度 var textFont:UIFont=UIFont.systemFont(ofSize:15) var imageV:UIButton? var lblmarquee:UILabel? //定义一个闭包,有参数没返回值 var infoMarqueeClickBlock:(Int)->()={ (Int)in return } var activityIndex:Int=0//记录是否第一次进入前台 override init(frame: CGRect) { super.init(frame: frame) self.backgroundColor=UIColor.white //注册进入前台的通知 NotificationCenter.default.addObserver(self, selector:#selector(becomeActive), name: UIApplication.didBecomeActiveNotification, object: nil) //注册进入后台的通知 NotificationCenter.default.addObserver(self, selector:#selector(becomeDeath), name: UIApplication.willResignActiveNotification, object: nil) } //必须要加@objc-----进入前台 @objc func becomeActive(noti:Notification){ if activityIndex==0{ activityIndex+=1 }else{ if scrollDerect{//水平滚动 index=headerScroll!.contentOffset.x }else { index=headerScroll!.contentOffset.y } //先吧定时器停止,再开始定时器,要不然速度会很快 stopTimer() startTimer() } print("进入前台") } //必须要加@objc----进后台 @objc func becomeDeath(noti:Notification){ print("进入后台") print("停止计时器") stopTimer() } func initviews(){ if headerScroll==nil{ headerScroll=UIScrollView.init(frame: CGRect(x: 0, y: 0, width:Int(WIDTH) , height:Int(self.frame.size.height))) } headerScroll!.delegate=self headerScroll?.showsHorizontalScrollIndicator=false //计算文本的大小 textFont=UIFont.systemFont(ofSize:sizefont)//注意:这里设置的大小要和文本的字体大小一致 realwidth = NSString(string: imageOrlblStr).boundingRect(with:CGSize(width: CGFloat(MAXFLOAT), height:0), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: textFont], context: nil).width+20 realHeight = NSString(string: imageOrlblStr).boundingRect(with:CGSize(width:100 , height:300), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: textFont], context: nil).height+20//这里cgsize要写一个实现的数据,不要写用CGFloat(MAXFLOAT) if lblstrOrimageName=="imageName"{ /** 显示图片,单张图片显示跑马灯 */ if imageV==nil{ imageV=UIButton.init(frame: CGRect(x:50, y:0, width:Int(WIDTH-60) , height:LUNBOHEIGHT)) } imageV!.setBackgroundImage(UIImage.init(named: imageOrlblStr), for: UIControl.State.normal) headerScroll!.addSubview(imageV!) imageV!.addTarget(self, action: #selector(imageVClick), for: UIControl.Event.touchUpInside) }else if lblstrOrimageName=="lblstr"{ /** 用label显示文字,跑马灯 */ if !scrollDerect{//竖直滚动的时候宽度等于屏幕宽度 if (lblmarquee != nil){ lblmarquee?.removeFromSuperview() } lblmarquee=UILabel.init(frame: CGRect(x:50, y:0, width:Int(WIDTH-50) , height:Int(realHeight))) lblmarquee!.font=UIFont.systemFont(ofSize: sizefont) lblmarquee!.text=imageOrlblStr lblmarquee!.numberOfLines=0 headerScroll!.addSubview(lblmarquee!) }else{//水平滚动 if (lblmarquee != nil){ lblmarquee?.removeFromSuperview() } lblmarquee=UILabel.init(frame: CGRect(x:50, y:0, width:Int(realwidth) , height:Int(50))) lblmarquee!.font=UIFont.systemFont(ofSize: sizefont) lblmarquee!.text=imageOrlblStr headerScroll!.addSubview(lblmarquee!) } } if scrollDerect{//水平滚动 if lblstrOrimageName=="imageName"{ headerScroll!.contentSize=CGSize(width: WIDTH+10, height: 0) }else { headerScroll!.contentSize=CGSize(width: realwidth+10, height: 0) } }else {//竖直滚动 if lblstrOrimageName=="imageName"{ headerScroll!.contentSize=CGSize(width:0, height:LUNBOHEIGHT+10) }else{ headerScroll!.contentSize=CGSize(width:0, height:realHeight+10) } } addSubview(headerScroll!) if !scrollDerect && realHeight<self.frame.size.height{//竖直滚动并且实际高度小于view的高度 }else{ startTimer()//定时器 } } //轮播图点击事件 @objc func imageVClick(sender:UIButton){ //tag是从102开始, print("\(sender.tag)") self.infoMarqueeClickBlock(0) } //正在滚动 func scrollViewDidScroll(_ scrollView: UIScrollView) { } //停止拖动--在didendDrag后面执行 func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollDerect{//水平滚动 index=headerScroll!.contentOffset.x }else { index=headerScroll!.contentOffset.y } //先吧定时器停止,再开始定时器,要不然速度会很快 stopTimer() startTimer() } var task:DispatchWorkItem? //刚开始拖拽 func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { print("停止计时器") stopTimer() } //停止拖拽----在DidEndDecelerating前执行 func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { print("开始计时器") if scrollDerect{//水平滚动 index=headerScroll!.contentOffset.x }else { index=headerScroll!.contentOffset.y } startTimer() } var timer : Timer? // .开始计时 func startTimer() { timer = Timer.scheduledTimer(timeInterval: 1/10, target: self, selector: #selector(autoScroll), userInfo: nil, repeats: true) //调用fire()会立即启动计时器 timer!.fire() } // 定时操作 @objc func autoScroll() { index+=CGFloat(2) if scrollDerect{//水平滚动 headerScroll!.setContentOffset(CGPoint.init(x: index, y: 0), animated: false) //合适的时候归位 if(index>=realwidth-20){ headerScroll!.setContentOffset(CGPoint.init(x: 0, y: 0), animated: false) index=0.0 } }else { headerScroll!.setContentOffset(CGPoint.init(x: 0, y: index), animated: false) //合适的时候归位 if(index>=realHeight*0.7){ headerScroll!.setContentOffset(CGPoint.init(x: 0, y: 0), animated: false) index=0.0 } } } // .停止计时器 func stopTimer() { if timer != nil { timer!.invalidate() //销毁timer timer = nil } } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }

 

转载请注明原文地址: https://www.6miu.com/read-4932762.html

最新回复(0)