實(shí)現(xiàn)無限輪播满钟,有很多的方法胜榔,網(wǎng)上也有很多方法,如果圖片不多湃番,完全可以用scrollview添加多個(gè)imageview的方法來實(shí)現(xiàn)(一般來說也不會(huì)有很多夭织,這個(gè)方法是添加了n + 2個(gè)imageview來實(shí)現(xiàn)輪播的,n就是你有多少條數(shù)據(jù))吠撮。還有就是用collectionview來實(shí)現(xiàn)尊惰,系統(tǒng)已經(jīng)有了復(fù)用cell的機(jī)制,所以不必?fù)?dān)心系統(tǒng)資源的問題泥兰。還有一個(gè)就是利用三個(gè)imageview來實(shí)現(xiàn)(也可以用兩個(gè)imageview來實(shí)現(xiàn)弄屡,但是相對(duì)來說三個(gè)imageview比較容易理解)這里,就采用三個(gè)imageview來實(shí)現(xiàn)一下這個(gè)功能鞋诗。
關(guān)于原理網(wǎng)絡(luò)上的講解已經(jīng)很多了膀捷,我這里只寫一下我自己封裝時(shí)候遇到一些需要注意的問題
??????源碼可以去文章后邊的地址下載哦??????
布局的東西,這里就不說了削彬,就是三個(gè)imageview依次添加到scrollview上邊全庸,(我這里使用的是本地的圖片,實(shí)際應(yīng)用中融痛,可以用kingfisher或者alamofireImage來請(qǐng)求壶笼,這兩個(gè)框架的使用方法,網(wǎng)上很多雁刷,可以自己學(xué)習(xí)一下哦)首先定義一個(gè)改變圖片的方法覆劈,這里有左滑和右滑兩個(gè)方向
//index表示是當(dāng)前顯示的位置,isRightScroll是滑動(dòng)方向
func changeImage(index:Int, isRightScroll:Bool){}
這里只寫一個(gè)向左滑動(dòng)的實(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
}
}
在這個(gè)方法判斷條件一定要寫好硼莽,scrollView.contentOffset.x == SCREEN_WIDTH * 2是沒問題的弥雹,有些大意的同學(xué)就會(huì)寫上一個(gè)scrollView.contentOffset.x >= SCREEN_WIDTH 認(rèn)為這樣就可以判斷是左滑了,那么就會(huì)出現(xiàn)一個(gè)問題,只要用戶滑動(dòng)址貌,就會(huì)改變圖片,這個(gè)是不符合需求的。
要實(shí)現(xiàn)自動(dòng)輪播练对,就需要定時(shí)器遍蟋,這里用GCD來實(shí)現(xiàn)
fileprivate func startTimer() {
gcd_timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)//注意,這里創(chuàng)建的隊(duì)列是主隊(duì)列
gcd_timer.scheduleRepeating(deadline: DispatchTime.now() + 3, interval: DispatchTimeInterval.seconds(3))
gcd_timer.setEventHandler { [weak self] in
self?.timerFire()
}
gcd_timer.resume()
定時(shí)器的觸發(fā)方法
//用來處理滾動(dòng)視圖的偏移量螟凭,改變圖片
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
})
}
為了避免跟用戶主動(dòng)滑動(dòng)時(shí)時(shí)間沖突虚青,實(shí)現(xiàn)以下兩個(gè)代理方法
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
gcd_timer.cancel()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
self.startTimer()
}
這里,這里螺男,如果在第一個(gè)代理里邊寫gcd_timer.suspend()棒厘,第二個(gè)里邊寫gcd_timer.resume()是不行的,具體原因下隧,還沒深究????
最后就是實(shí)現(xiàn)點(diǎn)擊方法了奢人,這里,只需要在中間的imageview上邊添加一個(gè)手勢(shì)就可以了(因?yàn)榭偸秋@示的是中間的那個(gè)imageview啦淆院,????)何乎,這個(gè)可以用代理寫,也直接用一個(gè)public的函數(shù)來讓子類繼承(這里只需要傳遞一個(gè)index土辩,也就是第幾條數(shù)據(jù)支救,就可以啦),我這里是用來protocol拷淘,個(gè)人感覺各墨,用繼承好像更簡(jiǎn)便????
func clickOneBanner(currentPage number:Int) {
let page = pageView.currentPage
if (self.bannerDelegate != nil) {
self.bannerDelegate?.clickOneBannerAction(currentPage: page)
}
}
好啦,到這里启涯,也就大功告成了欲主。你就可以擁有一個(gè)自己的無限輪播圖啦????,隨后會(huì)再寫一個(gè)用collectionview封裝的逝嚎,有需要的同學(xué)可以參看下扁瓢,如果有錯(cuò)誤之處,還望指正[抱拳][抱拳]
源碼下載地址:https://github.com/RenGuanXiao/RBannerView