Swift 動畫滾動的banner

原理概述

首先說一下整個banner工具的實現(xiàn)原理闽颇,所用控件主要是UICollectionView,頁碼UIPageControl寄锐,以及計時器Timer兵多。根據(jù)要滾動的數(shù)據(jù)顯示在三個section里面尖啡,每個section都展示所有的數(shù)據(jù),默認看到的是第二個section的某一頁面剩膘,當每次執(zhí)行定時器循環(huán)時先根據(jù)當前顯示的索引以迅雷不及掩耳之勢變?yōu)轱@示第二組的這個頁面衅斩,如果這個頁面是最后一個則下一個頁面就是第三組數(shù)據(jù)的第一個,因此不會導致回滾的尷尬怠褐。
里面使用了isAutoScrolling來判斷是否根據(jù)定時器滾動矛渴,當拖拽時定時器要注銷,使用isAutoScrolling能夠避免定時器與拖拽的沖突

使用

let bannerView = LYAnimateBannerView(frame: CGRect(x: 0, y: 0, width: kScreenW, height: kScreenW), delegate: self)
bannerView.backgroundColor = UIColor.white
bannerView.showPageControl = true
self.bannerView.imageUrlArray = arrM
if arrM.count < 2{
self.bannerView.showPageControl = false
}

源碼


import UIKit


protocol LYAnimateBannerViewDelegate {
func LY_AnimateBannerViewClick(banner:LYAnimateBannerView,index:NSInteger)
}

class LYAnimateBannerView: UIView {
enum LY_BannerType {
case ly_titleType
case ly_imageType
case ly_imageUrlType
}

var LY_AnimateBannerViewClickBlock : ((Int) -> Void)?
var showPageControl = false


fileprivate var delegate : LYAnimateBannerViewDelegate?
fileprivate var collectionView : UICollectionView!
fileprivate var timer : Timer?
fileprivate var type : LY_BannerType = .ly_titleType
fileprivate var pageControl : UIPageControl?
fileprivate var isAutoScrolling = false

var titleArray = Array<String>(){
didSet{
self.type = .ly_titleType
self.setUpCollectionView()
if self.titleArray.count > 1{
self.addTimer()
}
}
}
var imageArray = Array<UIImage>(){
didSet{
self.type = .ly_imageType
self.setUpCollectionView()
if self.imageArray.count > 1{
self.addTimer()
}
}
}
var imageUrlArray = Array<String>(){
didSet{
self.type = .ly_imageUrlType
self.setUpCollectionView()
if self.imageUrlArray.count > 1{
self.addTimer()
}
}
}

init(frame:CGRect,delegate:LYAnimateBannerViewDelegate) {
super.init(frame: frame)
self.frame = frame
self.delegate = delegate
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func setUpCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
layout.scrollDirection = self.type == .ly_titleType ? .vertical : .horizontal
layout.itemSize = CGSize.init(width: self.w, height: self.h)
self.collectionView = UICollectionView.init(frame: self.bounds, collectionViewLayout: layout)
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.collectionView.backgroundColor = UIColor.clear
self.collectionView.showsVerticalScrollIndicator = false
self.collectionView.showsHorizontalScrollIndicator = false
self.collectionView.isPagingEnabled = true
collectionView.register(UINib.init(nibName: "BannerScrollTitleCell", bundle: Bundle.main), forCellWithReuseIdentifier: "BannerScrollTitleCell")
collectionView.register(UINib.init(nibName: "BannerScrollImageCell", bundle: Bundle.main), forCellWithReuseIdentifier: "BannerScrollImageCell")
self.addSubview(self.collectionView)
self.collectionView.reloadData()

self.setUpPageControl()
}

//set pagecontrol
func setUpPageControl() {
//少于兩個的時候不用滾動
if self.collectionView.numberOfItems(inSection: 0) < 2{
return
}
if self.pageControl != nil{
self.pageControl = nil
self.pageControl?.removeFromSuperview()
}
self.pageControl = UIPageControl()
self.pageControl?.numberOfPages = self.collectionView.numberOfItems(inSection: 0)
self.pageControl?.currentPageIndicatorTintColor = UIColor.darkGray
self.pageControl?.pageIndicatorTintColor = UIColor.lightGray
self.pageControl?.frame = CGRect.init(x: 0, y: self.h - 30, width: self.w, height: 30)
self.addSubview(self.pageControl!)
}

//設(shè)置定時器
func addTimer()  {
if self.timer != nil{
self.removeTimer()
}

self.timer = Timer(timeInterval: 3.0, target: self, selector: #selector(LYAnimateBannerView.nextPage), userInfo: nil, repeats: true)
RunLoop.main.add(self.timer!, forMode: .defaultRunLoopMode)
timer!.fire()
self.isAutoScrolling = true
}
//移除定時器
func removeTimer() {
self.timer?.invalidate()
self.timer = nil
}

func nextPage() {

if !self.isAutoScrolling{
return
}

// 1.馬上顯示回最中間那組的數(shù)據(jù)
let currentIndexPathReset = self.resetIndexPath()
// 2.計算出下一個需要展示的位置
var nextItem = currentIndexPathReset.item + 1
var nextSection = currentIndexPathReset.section

if self.type == .ly_titleType{
if nextItem == self.titleArray.count {
nextItem = 0
nextSection += 1
}
}else if self.type == .ly_imageUrlType{
if nextItem == self.imageUrlArray.count {
nextItem = 0
nextSection += 1
}
}else{
if nextItem == self.imageArray.count {
nextItem = 0
nextSection += 1
}
}

let nextIndexPath = IndexPath.init(item: nextItem, section: nextSection)
// 3.通過動畫滾動到下一個位置
if self.type == .ly_titleType{
self.collectionView.scrollToItem(at: nextIndexPath, at: .top, animated: true)
}else{
self.collectionView.scrollToItem(at: nextIndexPath, at: .left, animated: true)
}

self.pageControl?.currentPage = nextItem
}

func resetIndexPath() -> IndexPath {
//current indexpath
guard let currentIndexPath = self.collectionView.indexPathsForVisibleItems.last else{
return IndexPath.init(item: 0, section: 2)
}
//馬上顯示回最中間那組的數(shù)據(jù)
let currentIndexPathReset = IndexPath.init(item: currentIndexPath.item, section: 2)
if self.type == .ly_titleType{
self.collectionView.scrollToItem(at: currentIndexPathReset, at: .top, animated: false)
}else{
self.collectionView.scrollToItem(at: currentIndexPathReset, at: .left, animated: false)
}
return currentIndexPathReset
}



}

extension LYAnimateBannerView : UICollectionViewDelegate, UICollectionViewDataSource{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 5
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if self.type == .ly_titleType{
return self.titleArray.count
}else if self.type == .ly_imageUrlType{
return self.imageUrlArray.count
}else{
return self.imageArray.count
}
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if self.type == .ly_titleType{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerScrollTitleCell", for: indexPath) as! BannerScrollTitleCell
if self.titleArray.count > indexPath.row{
cell.titleLbl.text = self.titleArray[indexPath.row]
}
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerScrollImageCell", for: indexPath) as! BannerScrollImageCell
if self.type == .ly_imageUrlType{
if self.imageUrlArray.count > indexPath.row{
cell.imgV.kf.setImage(with: URL(string:self.imageUrlArray[indexPath.row]))
}
}else{
if self.imageArray.count > indexPath.row{
cell.imgV.image = self.imageArray[indexPath.row]
}
}
return cell
}
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if self.LY_AnimateBannerViewClickBlock != nil{
self.LY_AnimateBannerViewClickBlock!(indexPath.row)
}else{
self.delegate?.LY_AnimateBannerViewClick(banner: self, index: indexPath.row)
}
}

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.removeTimer()
self.isAutoScrolling = false
}

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let currentIndexPathReset = self.resetIndexPath()
self.pageControl?.currentPage = currentIndexPathReset.item
self.addTimer()
}
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惫搏,一起剝皮案震驚了整個濱河市具温,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌筐赔,老刑警劉巖铣猩,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異茴丰,居然都是意外死亡达皿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門贿肩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來峦椰,“玉大人,你說我怎么就攤上這事汰规√拦Γ” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵溜哮,是天一觀的道長滔金。 經(jīng)常有香客問我,道長茂嗓,這世上最難降的妖魔是什么餐茵? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮述吸,結(jié)果婚禮上忿族,老公的妹妹穿的比我還像新娘。我一直安慰自己蝌矛,他們只是感情好道批,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著朴读,像睡著了一般屹徘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上衅金,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天噪伊,我揣著相機與錄音簿煌,去河邊找鬼。 笑死鉴吹,一個胖子當著我的面吹牛姨伟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播豆励,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼夺荒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了良蒸?” 一聲冷哼從身側(cè)響起技扼,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嫩痰,沒想到半個月后剿吻,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡串纺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年丽旅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纺棺。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡榄笙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出祷蝌,到底是詐尸還是另有隱情茅撞,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布杆逗,位于F島的核電站乡翅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏罪郊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一尚洽、第九天 我趴在偏房一處隱蔽的房頂上張望悔橄。 院中可真熱鬧,春花似錦腺毫、人聲如沸癣疟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睛挚。三九已至,卻和暖如春急黎,著一層夾襖步出監(jiān)牢的瞬間扎狱,已是汗流浹背侧到。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淤击,地道東北人匠抗。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像污抬,于是被迫代替她去往敵國和親汞贸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容