前言
見過很多的iOS應用,都有無限輪播圖宴霸,之前也看到過很多相關實現(xiàn)的文章,可是僅僅就是一看而過罷了膏蚓。當自己在項目中用到這個瓢谢,真正去寫的時候才發(fā)現(xiàn)不是很容易,遇到了一些問題驮瞧,這篇文章就記錄下自己最后成功實現(xiàn)輪播圖的歷程氓扛。
原理
原理其實就是一種假象。不過在我這里,目前有過兩種原理的實現(xiàn)采郎。一種利用UICollectionView
實現(xiàn)輪播千所,另一種利用UIScrollView
實現(xiàn)輪播。
今天我們要來打造一款這樣的輪播圖(圖畫的不好蒜埋,請勿見怪)淫痰。
原理一:利用UIScrollView
實現(xiàn)輪播圖。
要想實現(xiàn)這樣的效果整份,我們使用UIScrollView
包含image0待错,image1,image2的三個UIImageView
都是放在UIScrollView
里面的烈评,但是這樣的話是不可以實現(xiàn)輪播的火俄。要想實現(xiàn)輪播就要再在該UIScrollView
的左右兩側各加一張UIImageView
。在最后一張放image0讲冠, 第一張放image2瓜客。這樣的話當我們滾動到最后或者最前面的的時候,我們就把列表切換到相應的位置沟启。
原理二:利用UICollectionView
實現(xiàn)輪播圖忆家。
你當然可以利用原理一再用UICollectionView
實現(xiàn)一次。但是我這里采用一種偷懶的方式德迹,利用UICollectionView
的cell重用機制芽卿。創(chuàng)建個無數(shù)個cell,比如3x20000胳搞。當用戶第一次進來的我們就將UICollectionView滑到3x20000x0.5的位置卸例。然后利用cell.indexPath.item % 3
來對cell上的UIImageView進行image顯示。這種方式比較偷懶肌毅,在后來添加NSTimer自動輪播和點擊事件的時候也比較簡單筷转,不過有點大炮打小鳥的感覺。所以我在這里也只是介紹下原理悬而,如果你有興趣呜舒,可以自己嘗試去實現(xiàn)下。而且UICollectionView自帶一個方法- scrollToItemAtIndexPath:atScrollPosition:animated:
還比較厲害笨奠。
具體實現(xiàn)
針對原理一袭蝗,我就來簡單實現(xiàn)下。(我這里使用代碼創(chuàng)建,你也可以使用Storyboard創(chuàng)建,原理一樣)
創(chuàng)建工程般婆,創(chuàng)建BannerView.Swift
,添加初始化代碼如下:
/// 初始化scrollView
lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.delegate = self
scrollView.alwaysBounceVertical = false
scrollView.bounces = true
scrollView.pagingEnabled = true
scrollView.scrollEnabled = true
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
return scrollView
}()
/// 初始化pageControl
lazy var pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.currentPageIndicatorTintColor = UIColor.redColor()
pageControl.pageIndicatorTintColor = UIColor.whiteColor()
return pageControl
}()
/// 在init里調用setupSubviews即可
func setupSubviews() {
self.addSubview(scrollView)
self.addSubview(pageControl)
scrollView.translatesAutoresizingMaskIntoConstraints = false
pageControl.translatesAutoresizingMaskIntoConstraints = false
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[v]|", options: [], metrics: nil, views: ["v": scrollView]))
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[v]|", options: [], metrics: nil, views: ["v": scrollView]))
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[p(==20)]-10-|", options: [], metrics: nil, views: ["p": pageControl]))
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[p(==100)]-10-|", options: [], metrics: nil, views: ["p": pageControl]))
}
初始化UIScrollView:
func setupScrollView() {
/// 創(chuàng)建 (imageNames.count + 2)個UIImageView
for index in 0 ... (imageNmaes.count + 1) {
let imageView = UIImageView(frame: CGRect(x: self.width*CGFloat(index), y: 0, width: self.width, height: self.height))
var picName = String()
switch index {
case 0:
picName = imageNames[imageNames.count-1]
break
case imageNames.count + 1:
picName = imageNames[0]
break
default:
picName = imageNames[index-1]
break
}
// imageView.af_setImageWithURL(NSURL(string: picName)!)
imageView.image = UIImage(named: picName)
imageView.contentMode = .ScaleToFill
imageView.clipsToBounds = true
imageView.userInteractionEnabled = true
scrollView.addSubview(imageView)
}
scrollView.contentSize = CGSize(width: self.width * CGFloat(imageNames.count + 2), height: self.height)
scrollView.contentOffset = CGPoint(x: self.width, y: 0)
}
無限輪番的實現(xiàn)到腥。(重點)使用UIScrollViewDelegate協(xié)議。
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView == self.scrollView {
let contentOffsetX = scrollView.contentOffset.x
///向前滑動到第0張圖的時候蔚袍,滾到第三張圖
if contentOffsetX == 0 {
scrollView.contentOffset = CGPoint(x: self.width * CGFloat(self.imageNames.count), y: 0)
}
/// 跑到第三張圖的時候乡范,滾到第0張圖
if contentOffsetX == CGFloat(self.imageNames.count + 1)*self.width {
scrollView.contentOffset = CGPoint(x: self.width, y: 0)
}
/// 改變pageControl,這里要注意,一定要一定要一定要 - 0.5晋辆, 因為最前面的第0張圖一直不顯示渠脉。
let index = scrollView.contentOffset.x / self.width - 0.5
self.pageControl.currentPage = Int(index)
}
}
添加計時器
好了,做到這里栈拖,你已經(jīng)成功實現(xiàn)了輪播圖连舍,可是這個輪播圖是手動的,下面添加自動滾動涩哟。也很簡單,設置一個NSTimer計時器即可盼玄。代碼如下:
// MARK: - Timer
var timer: NSTimer?
var i = 1
/// 在scrollView上的圖片成功設置后調用startTimer即可
private func startTimer() {
if timer != nil {
self.stopTimer()
}
/// 這里設置的滾動間隔為2秒
timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: #selector(autoScroll), userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(timer!, forMode: NSDefaultRunLoopMode)
}
private func stopTimer() {
timer?.invalidate()
timer = nil
}
func autoScroll() {
if i == imageNames.count + 1 {
i = 1
}
i += 1
/// 在處理無限輪番的時候設置contentOffset沒有添加animated贴彼,這里要添加上來,不然有種很突兀的感覺埃儿。
scrollView.setContentOffset(CGPoint(x: self.width * CGFloat(i), y: 0), animated: true)
}
/// 手動滾動結束后恢復計時
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
self.startTimer()
}
/// 當手動滾動開始時停止計時
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
self.stopTimer()
}
添加具體點擊事件
具體到點擊事件的話器仗,我是放在初始化imageView那里處理的,給imageVIew添加一個UITapGestureRecognizer童番,在這里最好再寫一個代理方法精钮,將imageView的點擊事件傳遞出去。然后根據(jù)當前contentOffet.x / self.width
來將具體哪張圖片的事件傳遞出去剃斧。我就不用代碼展示了轨香。
結尾
還是比較簡單的。但是我這個復用性比較差幼东,封裝的也不好臂容,可是具體要看思路??。代碼實現(xiàn)放在了Github Wiki上了BannerView.Swift根蟹,由于工程量太小脓杉,就沒將工程文件上傳了。
關于作者
Qiuncheng简逮,一位正在iOS路上前行的初學者球散,正在努力成為一名合格的iOS開發(fā)者。