实现思路
- 依然是用到UIScrollView,不同的是这次运用重用的思想,因为不管我们有多少张图片要轮播,在UIScrollView上我们可以同时看到的始终只有两个UIImageView。换言之,只需要两个UIImageView即可实现。
- 在UIScrollView上的中心位置添加一个UIImageView,UIScrollView的contentOffset也设置成看到中间的UIImageView的位置,每次滚动时判断滚动的方向,在相应的位置展示另一个UIImageView。
- 在滚动结束时重新将UIScrollView的contentOffset设置为中心位置。
画图帮助理解一下:
蓝色代表UIScrollView,灰色框内是我们在UIScrollView上所看见的一切。首先我们按图中的Frame初始化控件。
当前UIImageView向左移动,将另外一个UIImageView的位置设置到当前UIImageView的右边。
当前UIImageView向右移动,将另外一个UIImageView的位置设置到当前UIImageView的左边。
代码
- 先看看需要用到哪些属性:
//自定义JHCarouseView类,继承自UIView,遵守UIScrollViewDelegate协议
class JHCarouseView: UIView,UIScrollViewDelegate {
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(scrollView)
scrollView.addSubview(currentImageView)
scrollView.addSubview(otherImageView)
addSubview(pageControl)
startTimer()
}
private var timer:NSTimer? //定时器-定时滚动图片
private lazy var scrollView:UIScrollView = {
let scrollView = UIScrollView.init(frame: CGRectMake(0, 0, self.bounds.width, self.bounds.height))
//可滑动宽度为自身的3倍
scrollView.contentSize = CGSizeMake(self.bounds.width*3, 0)
//可视位置为中心位置
scrollView.contentOffset = CGPointMake(self.bounds.width, 0)
scrollView.pagingEnabled = true
scrollView.showsHorizontalScrollIndicator = false
scrollView.delegate = self
return scrollView
}()
//当前可见的ImageView
private lazy var currentImageView:UIImageView = {
let currentImageView = UIImageView.init(frame: CGRectMake(self.bounds.width, 0, self.bounds.width, self.bounds.height))
currentImageView.image = self.imageArray[0]
return currentImageView
}()
//另一个ImageView的位置暂时不确定
private lazy var otherImageView = UIImageView()
//pageControl
private lazy var pageControl:UIPageControl = {
let pageControl = UIPageControl.init(frame: CGRectMake(self.bounds.width/2-30, CGRectGetMaxY(self.scrollView.frame), 60, 15))
pageControl.numberOfPages = self.imageArray.count
pageControl.pageIndicatorTintColor = UIColor.grayColor()
pageControl.currentPageIndicatorTintColor = UIColor.whiteColor()
return pageControl
}()
//轮播图片
private let imageArray = [UIImage.init(named: "helper_1"),UIImage.init(named: "helper_2")]
//定义一个方向枚举,用来判别ScrollView滑动方向
enum Direction {
case None
case Left
case Right
}
private var currentIndex = 0 //当前图片下标
private var nextIndex = 0 //滚动时应该显示的图片的下标
private var direction:Direction? {
didSet {//监听方向属性,在scrollViewDidScroll方法中赋值,请留意。
if direction == .Right {
otherImageView.frame = CGRectMake(0, 0, self.scrollView.bounds.size.width, self.scrollView.bounds.size.height)
self.nextIndex = self.currentIndex - 1
if self.nextIndex < 0 {
//循环显示,第一张到最后一张
self.nextIndex = imageArray.count - 1
}
} else if direction == .Left {
self.otherImageView.frame = CGRectMake(currentImageView.frame.maxX, 0, self.scrollView.bounds.size.width, self.scrollView.bounds.size.height)
self.nextIndex = (self.currentIndex + 1)%imageArray.count
}
//计算完index,记得给另外一个imageView.image赋值
self.otherImageView.image = self.imageArray[self.nextIndex]
pageControl.currentPage = currentIndex
}
}
}
- delegate方法部分:
//计算imageView移动的方向,给direction变量赋值,会自动调用didSet包含的代码
func scrollViewDidScroll(scrollView: UIScrollView) {
direction = scrollView.contentOffset.x > SCREEN_WIDTH-30 ? .Left : .Right //imageView移动的方向
}
//滑动快停止的时候,作一些处理
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
scrollDidStop()
}
private func scrollDidStop() {
self.direction = .None //清空方向
let index = scrollView.contentOffset.x/scrollView.bounds.size.width
if index == 1 { //说明滑动前与滑动后contentOffset并无变化,return
return
}
//将otherImageView设置成currentImageView,回到一开始的状态:位于UIScrollView中间的是currentImageView
currentImageView.frame = CGRectMake(scrollView.bounds.size.width, 0, scrollView.bounds.size.width, scrollView.bounds.size.height)
self.currentIndex = self.nextIndex
currentImageView.image = self.otherImageView.image
scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0)
}
- 定时滚动部分:
//启动定时器
func startTimer() {
if imageArray.count == 1 {
return
}
if timer != nil {//重置定时器
timer!.invalidate()
timer = nil
}
timer = NSTimer.init(timeInterval: 2, target: self, selector: #selector(self.nextPage), userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(timer!, forMode: NSRunLoopCommonModes)
}
func nextPage () {
scrollView.setContentOffset(CGPointMake(scrollView.bounds.width*2, 0), animated: true)
//调用完setContentOffset方法系统自动调用 scrollViewDidEndScrollingAnimation方法
}
func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
scrollDidStop() //滑动结束后作处理
}
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
timer?.invalidate() //用户拖动时停止定时器
}
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
startTimer()//松开后再次启动定时器
}
以上。