swift3 循环滚动视图 自适应横竖屏 reload数据源

一句话创建banner图,可时时刷新
用到了 SnapKit、SDWebImage两个第三方库
实现步骤----------------------------------------------------
import UIKit
typealias BtnBlock = (Int) -> Void
//ImagesBlock
typealias ImagesBlock = () -> [String]
class CycleView: UIView,UIScrollViewDelegate {
//MARK: - 私有属性
private var btnBlock:BtnBlock? //block
private var imageBlock:ImagesBlock?
private var scrollView: UIScrollView?
private var pageControl: UIPageControl?
private var images:[UIImage]?
private var imageStrs:[String]?
private var timer: Timer?
private var currentPage = 0 {
didSet {
pageControl?.currentPage = currentPage
resetImageViewSource()
}
}
//MARK: - 给外部调用的属性
var rollingTime: TimeInterval = 2.0 //滚动一页的时间
var rollingEnable: Bool = false { //是否自动滚动
willSet {
if newValue != rollingEnable {
if newValue {
startTimer()
} else {
stopTimer()
}
}
}
}
//MARK: - 刷新数据
public func reloadCyc(){
imageStrs = imageBlock?()
pageControl?.numberOfPages = (imageStrs?.count)!
if imageStrs?.count != 0{
currentPage = 0
if imageStrs?.count == 1{
stopTimer()
scrollView?.isScrollEnabled = false
}else{
startTimer()
scrollView?.isScrollEnabled = true
}
}else{
stopTimer()
scrollView?.isScrollEnabled = false
for i in 0..<3 {
let img = scrollView?.subviews[i] as! UIImageView
img.image = nil
}
}
}
//MAKR:- 暴露创建对象方法
/// 获取到一个滚动视图
///
/// - parameter imageSourceBlock: image数据block
/// - parameter btnBlk: scroview点击block
///
/// - returns: CycleView对象
static func showCycView(imageSourceBlock:ImagesBlock?,btnBlk:BtnBlock?) -> CycleView {
let cycView = CycleView()
cycView.showCycView(imageSourceBlock: imageSourceBlock, btnBlk: btnBlk)
return cycView
}
//私有对象方法
private func showCycView(imageSourceBlock:ImagesBlock?,btnBlk:BtnBlock?) -> Void{
imageBlock = imageSourceBlock
btnBlock = btnBlk
setUI()
self.reloadCyc()
startTimer()
}
//创建UI
private func setUI(){
scrollView = UIScrollView()
self.addSubview(scrollView!)
scrollView?.backgroundColor = UIColor.gray
scrollView?.snp.makeConstraints({ (make) in
make.top.left.bottom.right.equalToSuperview()
})
scrollView?.showsHorizontalScrollIndicator = false
scrollView?.showsVerticalScrollIndicator = false
scrollView?.isPagingEnabled = true
scrollView?.bounces = false
scrollView?.delegate = self
scrollView?.addSubview(UIImageView())
scrollView?.addSubview(UIImageView())
scrollView?.addSubview(UIImageView())
let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapAction))
scrollView?.addGestureRecognizer(tap)
pageControl?.isEnabled = false
pageControl = UIPageControl()
pageControl?.currentPage = 0
pageControl?.isUserInteractionEnabled = false
pageControl?.currentPageIndicatorTintColor = UIColor.green
pageControl?.pageIndicatorTintColor = UIColor.gray
self.addSubview(pageControl!)
pageControl?.snp.makeConstraints({ (make) in
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
make.bottom.equalToSuperview().offset(-20)
make.height.equalTo(30)
})
}
//MARK:- 自动滚动
//开始滚动
private func startTimer() {
if timer==nil {
timer = Timer.scheduledTimer(timeInterval: rollingTime, target: self, selector: #selector(scrollForTime(time:)), userInfo: nil, repeats: true)
}
}
//停止滚动
private func stopTimer() {
if(timer != nil){
timer!.invalidate()
timer = nil
}
}
//滚动事件
func scrollForTime(time:Timer) -> Void {
scrollView?.setContentOffset(CGPoint(x: self.frame.size.width * 2, y: 0), animated: true)
}
//MARK:- 适配scroview及image
override func layoutSubviews() {
super.layoutSubviews()
scrollView?.contentSize = CGSize(width: self.frame.size.width * 3, height: self.frame.size.height)
scrollView?.setContentOffset(CGPoint(x: self.frame.size.width * 2, y: 0), animated: false)
for i in 0..<3 {
let img = scrollView?.subviews[i] as! UIImageView
img.contentMode = .scaleAspectFit
img.clipsToBounds = true
img.frame = CGRect(x: CGFloat(i) * (scrollView?.frame.size.width)!, y: 0, width: (scrollView?.frame.size.width)!, height: (scrollView?.frame.size.height)!)
}
}
//MARK:-每当滚动后重新设置各个imageView的图片
func resetImageViewSource() {
let placeholderImage = UIImage(named: "placeholder.png")
let leftImageView = scrollView?.subviews[0] as! UIImageView
let middleImageView = scrollView?.subviews[1] as! UIImageView
let rightImageView = scrollView?.subviews[2] as! UIImageView
//当前显示的是第一张图片
if currentPage == 0 {
leftImageView.sd_setImage(with: URL.init(string: (imageStrs?.last)!), placeholderImage: placeholderImage)
middleImageView.sd_setImage(with: URL.init(string: (imageStrs?[currentPage])!), placeholderImage: placeholderImage)
let rightImageIndex = (imageStrs?.count)!>1 ? 1 : 0 //保护
rightImageView.sd_setImage(with: URL.init(string: (imageStrs?[rightImageIndex])!), placeholderImage: placeholderImage)
}//当前显示的是最后一张图片
else if currentPage == (imageStrs?.count)! - 1 {
leftImageView.sd_setImage(with: URL.init(string: (imageStrs?[currentPage-1])!), placeholderImage: placeholderImage)
middleImageView.sd_setImage(with: URL.init(string: (imageStrs?[currentPage])!), placeholderImage: placeholderImage)
rightImageView.sd_setImage(with: URL.init(string: (imageStrs?[0])!), placeholderImage: placeholderImage)
}//其他情况
else{
leftImageView.sd_setImage(with: URL.init(string: (imageStrs?[currentPage-1])!), placeholderImage: placeholderImage)
middleImageView.sd_setImage(with: URL.init(string: (imageStrs?[currentPage])!), placeholderImage: placeholderImage)
rightImageView.sd_setImage(with: URL.init(string: (imageStrs?[currentPage+1])!), placeholderImage: placeholderImage)
}
scrollView?.setContentOffset(CGPoint(x: self.frame.size.width, y: 0), animated: false)
}
//MARK: - scrollViewDelegate
//setContentOffset的动画完成后会调用,使currentPage+1
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
if imageStrs?.count != 0{
currentPage = (currentPage+1)%(imageStrs?.count)!
}
}
//拖动scrollView时会停止自动滚动
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if rollingEnable {
stopTimer()
}
}
//停止拖动后会重新开始自动滚动
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if rollingEnable {
startTimer()
}
scrollView.isScrollEnabled = false
}
//拖动scrollView时当减速动画结束时调用
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
scrollView.isScrollEnabled = true
if imageStrs?.count != 0{
if scrollView.contentOffset.x == 0 { //向前滑动
if currentPage == 0 {
currentPage = (imageStrs?.count)!-1
} else {
currentPage -= 1
}
} else if scrollView.contentOffset.x == 2 * self.frame.size.width { //向后滑动
currentPage = (currentPage+1)%(imageStrs?.count)!
}
}
}
//MARK:- 点击图片回调事件
func tapAction() {
if imageStrs?.count != 0{
btnBlock?(currentPage)
}
}
}
调用方法----------------------
import UIKit
import SnapKit
import SDWebImage
class ViewController: UIViewController {
var imageStrs = [String]()
var cyc : CycleView?
override func viewDidLoad() {
super.viewDidLoad()
self.automaticallyAdjustsScrollViewInsets = false
setUI()
}
func setUI(){
cyc = CycleView.showCycView(imageSourceBlock: { () -> [String] in
return self.imageStrs //返回图片url,若要支持本地图片,自行修改
}) { (tag) in
print("tag:\(tag)")//图片点击回调
}
self.view.addSubview(cyc!)
cyc?.rollingTime = 4
cyc?.snp.makeConstraints { (make) in
make.left.right.equalToSuperview().offset(0)
make.top.equalToSuperview().offset(20)
make.height.equalTo(230)
}
let btn = UIButton(type: UIButtonType.system)
btn.setTitle("增加image", for: UIControlState.normal)
self.view.addSubview(btn)
btn.tag = 1
btn.addTarget(self, action: #selector(btnAction(btn:)), for: UIControlEvents.touchUpInside)
btn.snp.makeConstraints { (make) in
make.center.equalToSuperview()
make.width.equalTo(100)
make.height.equalTo(30)
}
let btn2 = UIButton(type: UIButtonType.system)
btn2.setTitle("减少image", for: UIControlState.normal)
self.view.addSubview(btn2)
btn2.tag = 2
btn2.addTarget(self, action: #selector(btnAction(btn:)), for: UIControlEvents.touchUpInside)
btn2.snp.makeConstraints { (make) in
make.centerX.equalTo(btn.snp.centerX)
make.centerY.equalTo(btn.snp.centerY).offset(100)
make.width.equalTo(100)
make.height.equalTo(30)
}
}
var count = 0
func btnAction(btn:UIButton){
let str1 = "http://d.hiphotos.baidu.com/image/pic/item/f9dcd100baa1cd11c1c35727bb12c8fcc3ce2dbb.jpg"
let str2 = "http://c.hiphotos.baidu.com/image/pic/item/6c224f4a20a4462323289f659a22720e0df3d7d2.jpg"
let str3 = "http://d.hiphotos.baidu.com/image/pic/item/7dd98d1001e939014acbb73979ec54e737d196ef.jpg"
let str4 = "http://i.zeze.com/attachment/forum/201502/09/122834pcd2q5l5dcnd4nqc.jpg"
let str5 = "http://img0.imgtn.bdimg.com/it/u=2176846966,1717026392&fm=21&gp=0.jpg"
let str6 = "http://b.hiphotos.baidu.com/zhidao/wh=450,600/sign=457d1fcc2c2eb938ec3872f6e052a903/21a4462309f7905289b85b130ff3d7ca7bcbd573.jpg"
let str7 = "http://img2.imgtn.bdimg.com/it/u=2553369102,2423460114&fm=21&gp=0.jpg"
let str8 = "http://img0.imgtn.bdimg.com/it/u=3230797900,10373402&fm=21&gp=0.jpg"
let str9 = "http://img4.imgtn.bdimg.com/it/u=1432393253,809810063&fm=21&gp=0.jpg"
let arr = [str1,str2,str3,str4,str5,str6,str7,str8,str9]
if btn.tag == 1{
if count >= arr.count{
imageStrs.removeAll()
count = 0;
}
imageStrs.append(arr[count])
cyc?.reloadCyc()
count += 1
}else{
if imageStrs.count != 0{
imageStrs.removeLast()
cyc?.reloadCyc()
count -= 1
}else{
count = 0
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
demo下载地址
swift3 循环滚动视图 自适应横竖屏 reload数据源的更多相关文章
- IOS实现自动循环滚动广告--ScrollView的优化和封装
一.问题分析 在许多App中,我们都会见到循环滚动的视图,比如广告,其实想实现这个功能并不难,用ScrollView就可以轻松完成,但是在制作的过程中还存在几个小问题,如果能够正确的处理好这些小问题, ...
- UIScrollView循环滚动1
现在基本每一个商业APP都会有循环滚动视图,放一些轮播广告之类的,都是放在UIScrollView之上.假如我要实现N张图片的轮播,我借鉴了几个博文,得到两种方法实现: [第一种]:如下图(图片来源于 ...
- layoutSubviews中判断横竖屏
在ContentView中重写layoutSubviews方法,然后根据stausbar的方向判断当前视图的横竖屏.具体代码: -(void)layoutSubviews{ [super layout ...
- 【IOS界面布局】横竖屏切换和控件自适应(推荐)
[IOS界面布局]横竖屏切换和控件自适应(推荐) 分类: [MAC/IOS下开发]2013-11-06 15:14 8798人阅读 评论(0) 收藏 举报 横竖屏切换 自适应 第一种:通过人为的办法改 ...
- iOS 之 设置横竖屏及ViewWillAppear及视图与导航控制器嵌套时的不同反应
设置横竖屏不成功,可能跟所在导航控制器有关 视图没有导航控制器时,又有可能不调用ViewWillAppear,这是我遇到的问题.
- iOS横竖屏切换的一些坑(持续更新)
最近在做视频类的App,遇到视频滚动播放的坑,紧接着就是横竖屏问题.之前太过天真不想做横竖屏配置.只是想旋转视频View,但是分享什么的包括AlertView还是竖屏样式,项目着急上线(1周提交一次也 ...
- 从零開始学android<ScrollView滚动视图.十八.>
因为手机屏幕的高度有限.所以假设面对组件要显示多组信息的时候,ScrollView视图(滚动视图)能够有效的安排这些组件,浏览时能够自己主动的进行滚屏的操作. android.widget.Scrol ...
- Android零基础入门第76节:Activity数据保存和横竖屏切换
在前面几期学习了Activity的创建.配置.启动和停止,还学了Activity的生命周期,本期一起来学习Activity有关的更多事儿. 一.数据保存 通过上一期 LogCat 窗口打印的日志可以看 ...
- iOS学习笔记——滚动视图(scrollView)
滚动视图:在根视图中添加UIScrollViewDelegate协议,声明一些对象属性 @interface BoViewController : UIViewController<UIScro ...
随机推荐
- MongoDB:利用官方驱动改装为EF代码风格的MongoDB.Repository框架 五 --- 为List<MongoDBRef>增加扩展方法
本次改动主要内容:为List<MongoDBRef>增加扩展方法 在MongoDB.Repository的使用过程中,发现在一个类中只定义一个List<MongoDBRef>是 ...
- P2P中的NAT穿越方案简介
文章链接: http://www.shipin.it/Index/videolist/id/68.html
- Linux环境进程间通信(二): 信号(上)
linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...
- yii2.0 文件上传
Yii 2.0 出来好长时间了,一直都是看下官方网站,没实践过,今天弄了下图片上传操作. 1创建一个简单的数据表 mysql> desc article; +---------+-------- ...
- C#对html的操作
1,获取相对路径的html然后保存到本地路径 /// <summary> /// Html方法 /// </summary> /// <returns></r ...
- Redis系统学习 三、使用数据结构
前言:上一章,简单介绍了5种数据结构,并给出了一些用例.现在是时候来看看一些高级的,但依然很常见的主题和设计模式 一.大O表示法(Big O Notation ) 常用时间复杂度O(1)被认为是最快速 ...
- Java笔记:内部类
1.把一个类放在另一类内部定义,这个定义在其他类里面的类就叫做内部类,包含内部类的类叫做外部类.内部类成员可以直接访问外部类的私有数据,但是外部类不能访问内部类的实现细节. 2.非静态内部类(没有st ...
- 发布Activex全过程
C#制作.打包.签名.发布Activex全过程 一.前言 最近有这样一个需求,需要在网页上面启动客户端的软件,软件之间的通信.调用,单单依靠HTML是无法实现了,因此必须借用Activex来实现.由于 ...
- offsetWidth, offsetHeight, offsetLeft, offsetTop,clientWidth, clientHeight,clientX,pageX,screenX
offsetWidth: 元素在水平方向上占用的空间大小.包括元素的宽度,内边距,(可见的)垂直滚动条的宽度,左右边框的宽度. offsetHeight:元素在垂直方向上占用的空间大小,包括元素的高度 ...
- c# AutoResetEvent和ManualResetEvent
网上有很多AutoResetEvent和ManualResetEvent的详细介绍,在这里不做过多详细的解释,写下自己的一点心得留作备忘. AutoResetEvent和ManualResetEven ...