图片轮播的几种实现思路:https://www.jianshu.com/p/54a6ecea22e2
轮播框架:WRCycleScrollView------https://github.com/wangrui460/WRCycleScrollView
===========简易实现图片轮播:==================
/**
首页轮播view
思路:假如图片数组有三个元素,把最后一个元素加到第一个之前,吧第一个元素加到最后一个,总共就有了五个元素,开始的时候设置偏移量默认显示第二张图片。当在第四个元素向右滑的时候,设置setcontentoffset到第二张图(也就是原始数组的第一张图),当从第二张图(也就是原始数组的第一张图)想左滑动的时候,设置setcontentoffset到第四张图(也就是原始数组的最后一张图)
使用:
lazy var lunbo:LYBHomelunboview={
let headerscroll = LYBHomelunboview.init(frame: CGRect(x: 0, y: 0, width:Int(WIDTH) , height:LUNBOHEIGHT))
return headerscroll
}()
lunbo.urlStrOrimageName="imageName"//imageName表示,传递图片名数组,默认是“”,表示传递的是url字符串
lunbo.scrollImages=["bankBlue","bankGreen","bankRed","appstart"]//相当于重写set方法,如果传的是url字符串,上面的urlStrOrimageNameURL不要设置。
lunbo.scrollClickBlock={
[weak self]//解决循环引用
(index) in
//传过来的tag,是从2开始
switch index {
case 0:break
case 1: break
case 2:
print("\(index)")
break
case 3:
break
default: break
}
return
}
*/
/**
http:www.ddb.cn/Api/Index/phoneBanner
无参数
*/
import UIKit
class LYBHomelunboview: LYBBaseView,UIScrollViewDelegate{
//属性观察器,相当于重写属性的set方法didset方法中scrollImages是新值,oldValue是旧值(固定写法)
var scrollImages:[String]!=["appstart"]{
willSet(scrollImagess) {
print("新的值\(String(describing: scrollImages))")
}
didSet {
print("新的值 \(String(describing: scrollImages))")
print("旧的值 \(String(describing: oldValue)) ")
initviews()//有数据了创建轮播
}
}
//懒加载---用到的时候才开始加载
lazy var images:[String]={
var newimages:[String]=scrollImages ?? ["appstart"]
newimages.insert(scrollImages![((scrollImages?.count)!-1)], at:0)//吧scrollImages的第一个元素插入到最后一个位置,组成新数组
newimages.append(scrollImages![0])//scrollImages的第一个元素插到最后一个位置
return newimages
}()
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=0//定时器滚动的页码
var btnArr:[AnyObject]?//轮播按钮的数组
//定义一个闭包,有参数没返回值
var scrollClickBlock:(Int)->()={ (Int)in return }
override init(frame: CGRect) {
super.init(frame: frame)
}
func initviews(){
headerScroll=UIScrollView.init(frame: CGRect(x: 0, y: 0, width:Int(WIDTH) , height:LUNBOHEIGHT))
headerScroll!.delegate=self
headerScroll?.showsHorizontalScrollIndicator=false
for i in 1...images.count {
let imageV:UIButton=UIButton.init(frame: CGRect(x:(i-1)*Int(WIDTH), y:0, width:Int(WIDTH) , height:LUNBOHEIGHT))
if urlStrOrimageName=="imageName"{
/**
图片名字符串
*/
imageV.setBackgroundImage(UIImage.init(named: images[i-1]), for: UIControl.State.normal)
}else{
/**
url显示图片
*/
do{
let imageData:Data=try Data.init(contentsOf: URL.init(string: images[i-1])!)
imageV.setBackgroundImage(UIImage.init(data: imageData), for: UIControl.State.normal)
}catch{
}
}
headerScroll!.addSubview(imageV)
imageV.addTarget(self, action: #selector(imageVClick), for: UIControl.Event.touchUpInside)
imageV.tag=100+i
btnArr?.append(imageV)
}
headerScroll!.contentSize=CGSize(width: WIDTH*CGFloat(images.count)+10, height: 0)
addSubview(headerScroll!)
DispatchQueue.main.async {//主线程一步是为了防止卡顿出现前面预设的一张图
self.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?.currentPageIndicatorTintColor=UIColor.red
pagectr?.pageIndicatorTintColor=UIColor.gray
pagectr?.currentPage=0
if isDisplayIndicator{//控制指示器显示
self.addSubview(pagectr!)
}
startTimer()//定时器
}
//轮播图点击事件
@objc func imageVClick(sender:UIButton){
//tag是从102开始,
print("\(sender.tag)")
let btntag=sender.tag-102//转化成从0开始
self.scrollClickBlock(btntag)
}
//正在滚动
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//和上一次的偏移量做比较,判断滑动的方向
if scrollView.contentOffset.x > lastOffset{
// print("向左边滑动")
derectStr="left"
}else{
// print("向右边滑动")
derectStr="right"
}
// 吧本次的偏移量计作为上一次的偏移
lastOffset=scrollView.contentOffset.x
}
//停止拖动--在didendDrag后面执行
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
index=Int(scrollView.contentOffset.x/WIDTH)//获取当前的偏移量
// 吧本次的偏移量计作为上一次的偏移
lastOffset=scrollView.contentOffset.x
DispatchQueue.main.async {
self.commonscroll()
}
}
var task:DispatchWorkItem?
//刚开始拖拽
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
print("停止计时器")
stopTimer()
//延时2秒执行
if let task=task{//如果task存在
//取消延迟执行的任务
print("取消延迟任务")
task.cancel()
}
}
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//偏移到第二张图片
lastOffset=(headerScroll?.contentOffset.x)!
}
}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 //偏移到倒数第二张图片
lastOffset=(headerScroll?.contentOffset.x)!
}
}
if Int(index)==0 {
}
else if Int(index)==images.count-1{
}else {
pagectr?.currentPage = Int((headerScroll?.contentOffset.x)!/WIDTH)-1
}
}
//停止拖拽----在DidEndDecelerating前执行
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
print("开始计时器")
index=Int(headerScroll!.contentOffset.x/WIDTH)+1//当前页码
DispatchQueue.main.async {
self.commonscroll()
}
//延时2秒执行
task = DispatchWorkItem {
print("延迟执行")
self.startTimer()
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2, execute: task!)
}
var timer : Timer?
// .开始计时
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(autoScroll), userInfo: nil, repeats: true)
//调用fire()会立即启动计时器
timer!.fire()
}
// 定时操作
@objc func autoScroll() {
headerScroll!.setContentOffset(CGPoint.init(x: 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: false)
pagectr?.currentPage = Int((headerScroll?.contentOffset.x)!/WIDTH)-1
}
index+=1//swift中不支持++,--
}
// .停止计时器
func stopTimer() {
if timer != nil {
timer!.invalidate() //销毁timer
timer = nil
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
================跑马灯=====================
跑马灯: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")
}
}