實(shí)現(xiàn)無限輪播,有很多的方法,網(wǎng)上也有很多方法,如果圖片不多,完全可以用scrollview添加多個imageview的方法來實(shí)現(xiàn)(一般來說也不會有很多,這個方法是添加了n + 2個imageview來實(shí)現(xiàn)輪播的,n就是你有多少條數(shù)據(jù))。還有就是用collectionview來實(shí)現(xiàn),系統(tǒng)已經(jīng)有了復(fù)用cell的機(jī)制,所以不必?fù)?dān)心系統(tǒng)資源的問題。還有一個就是利用三個imageview來實(shí)現(xiàn)(也可以用兩個imageview來實(shí)現(xiàn),但是相對來說三個imageview比較容易理解)這里,就采用三個imageview來實(shí)現(xiàn)一下這個功能。
關(guān)于原理網(wǎng)絡(luò)上的講解已經(jīng)很多了,我這里只寫一下我自己封裝時候遇到一些需要注意的問題
??????源碼可以去文章后邊的地址下載哦??????
布局的東西,這里就不說了,就是三個imageview依次添加到scrollview上邊,(我這里使用的是本地的圖片,實(shí)際應(yīng)用中,可以用kingfisher或者alamofireImage來請求,這兩個框架的使用方法,網(wǎng)上很多,可以自己學(xué)習(xí)一下哦)首先定義一個改變圖片的方法,這里有左滑和右滑兩個方向
//index表示是當(dāng)前顯示的位置,isRightScroll是滑動方向
func changeImage(index:Int, isRightScroll:Bool){}
這里只寫一個向左滑動的實(shí)現(xiàn),具體實(shí)現(xiàn),可以去源碼看
//左滑
if !isRightScroll {
if index < totalPage - 2 {
leftImageView.image = imageAry[index]
midImageView.image = imageAry[index + 1]
rightImageView.image = imageAry[index + 2]
return
}
if index == totalPage - 2 {
leftImageView.image = imageAry[index]
midImageView.image = imageAry[index + 1]
rightImageView.image = imageAry[0]
return
}
if index == totalPage - 1 {
leftImageView.image = imageAry[index]
midImageView.image = imageAry[0]
rightImageView.image = imageAry[1]
return
}
}
接下來就是要實(shí)現(xiàn)scrollview的代理方法了
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView){
// 向左滑
if scrollView.contentOffset.x == SCREEN_WIDTH * 2 {
self.changeImage(index: currentIndex, isRightScroll: false)
if currentIndex < totalPage - 1 {
currentIndex += 1
}else {
currentIndex = 0
}
pageView.currentPage = currentIndex
}
}
在這個方法判斷條件一定要寫好,scrollView.contentOffset.x == SCREEN_WIDTH * 2是沒問題的,有些大意的同學(xué)就會寫上一個scrollView.contentOffset.x >= SCREEN_WIDTH 認(rèn)為這樣就可以判斷是左滑了,那么就會出現(xiàn)一個問題,只要用戶滑動,就會改變圖片,這個是不符合需求的。
要實(shí)現(xiàn)自動輪播,就需要定時器,這里用GCD來實(shí)現(xiàn)
fileprivate func startTimer() {
gcd_timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)//注意,這里創(chuàng)建的隊列是主隊列
gcd_timer.scheduleRepeating(deadline: DispatchTime.now() + 3, interval: DispatchTimeInterval.seconds(3))
gcd_timer.setEventHandler { [weak self] in
self?.timerFire()
}
gcd_timer.resume()
定時器的觸發(fā)方法
//用來處理滾動視圖的偏移量,改變圖片
func timerFire() {
UIView.animate(withDuration: 0.5, animations: {[weak self] in
self?.bottomScrollView.contentOffset.x = SCREEN_WIDTH * 2
self?.midImageView.isUserInteractionEnabled = false
}, completion: {[weak self] (bool) in
self?.changeImage(index: (self?.currentIndex)!, isRightScroll: false)
if (self?.currentIndex)! < (self?.totalPage)! - 1 {
self?.currentIndex += 1
}else {
self?.currentIndex = 0
}
self?.pageView.currentPage = (self?.currentIndex)!
self?.bottomScrollView.contentOffset = CGPoint.init(x: SCREEN_WIDTH, y: 0)
self?.midImageView.isUserInteractionEnabled = true
})
}
為了避免跟用戶主動滑動時時間沖突,實(shí)現(xiàn)以下兩個代理方法
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
gcd_timer.cancel()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
self.startTimer()
}
這里,這里,如果在第一個代理里邊寫gcd_timer.suspend(),第二個里邊寫gcd_timer.resume()是不行的,具體原因,還沒深究????
最后就是實(shí)現(xiàn)點(diǎn)擊方法了,這里,只需要在中間的imageview上邊添加一個手勢就可以了(因為總是顯示的是中間的那個imageview啦,????),這個可以用代理寫,也直接用一個public的函數(shù)來讓子類繼承(這里只需要傳遞一個index,也就是第幾條數(shù)據(jù),就可以啦),我這里是用來protocol,個人感覺,用繼承好像更簡便????
func clickOneBanner(currentPage number:Int) {
let page = pageView.currentPage
if (self.bannerDelegate != nil) {
self.bannerDelegate?.clickOneBannerAction(currentPage: page)
}
}
好啦,到這里,也就大功告成了。你就可以擁有一個自己的無限輪播圖啦????,隨后會再寫一個用collectionview封裝的,有需要的同學(xué)可以參看下,如果有錯誤之處,還望指正[抱拳][抱拳]
源碼下載地址:https://github.com/RenGuanXiao/RBannerView