swift:無限圖片輪播器
圖片輪播器用處很廣兜挨,什么廣告投放呀替久,新聞頭條滾動之類的箱锐,都是使用它。出于學(xué)習(xí)的目的用swift基于UICollectionView開發(fā)了一個無限循環(huán)的圖片輪播器埋同。附上Github源碼以及素材地址CyclePictureView州叠。下面是演示
適合人群
用swift寫了一個無限圖片輪播器,適合初學(xué)者莺禁。為了方便大家一步步自己開發(fā)留量,已經(jīng)把開發(fā)過程中的每一個階段都用了一個工程窄赋,當(dāng)然你也可以使用git回滾哟冬。而且在功能基本完成后楼熄,花了很大的心思對代碼進(jìn)行重構(gòu),讓代碼更加符合swift的編程模式浩峡。
編碼
1.完成本地圖片的顯示
- 創(chuàng)建CyclePictureView.swift這是我們圖片輪播器主要的view可岂,在這一階段,我僅僅只是利用UIColleciotnView的流水布局效果達(dá)成了一個簡單的效果翰灾。
- 創(chuàng)建CyclePictureCell.swift缕粹。這個是用于UIColleciotnView的cell,它代表顯示的每一張圖片
- 創(chuàng)建LocalPictureController.swift,用于測試
這一階段十分簡單纸淮,大家參照源碼1.完成本地圖片的顯示工程應(yīng)該不會有問題
2.完成網(wǎng)絡(luò)圖片的顯示
- 添加了網(wǎng)絡(luò)圖片加載的功能平斩,這里我沒有自己重寫圖片加載過程直接調(diào)用第三方框架Kingfisher,這個框架和oc的SDWebImage十分類似。其實事后我才發(fā)現(xiàn)Kingfisher跟SDWebImage的差距還是有很大咽块。如果想使用其他框架列如SDWebImage只需將CyclePictureCell中設(shè)置圖片的kf_setImageWithURL改成sd_setImageWithURL绘面。
- 創(chuàng)建WebPictureController.swift,用于對網(wǎng)絡(luò)數(shù)據(jù)的測試侈沪,我提供了一個Image.plist文件揭璃,里面是一些網(wǎng)絡(luò)圖片的url和圖片對應(yīng)的描述。
這一階段如果是有經(jīng)驗的開發(fā)者就對我實現(xiàn)這兩種圖片加載的方式感到不爽了亭罪,因為這里是可以對代碼進(jìn)行重構(gòu)的瘦馍。當(dāng)然,對于初學(xué)者的我們应役,一定要以實現(xiàn)功能為主如果在項目一開始就考慮代碼這樣寫不好情组,那樣寫不好。那么你永遠(yuǎn)可能也邁不出項目第一步箩祥,會嚴(yán)重拖緩開發(fā)進(jìn)度呻惕。所以我們先實現(xiàn)功能,對于代碼的重構(gòu)滥比,一個階段一個階段的來亚脆,或者說你啥時候?qū)嵲谌滩涣肆耍蔷驼泶a吧盲泛。
3.完成文字顯示濒持,并暴露一些接口
- 添加了圖片的描述文字,并暴露了一些接口寺滚。因為我們開發(fā)這個圖片輪播器是想以后自己能夠用到柑营,而往往對于不同規(guī)格的圖片輪播器,我們對于文字的大小什么的可能會不一樣村视。所以這些屬性必須提供給用戶官套,讓使用者能夠自己定制。
這里需要注意一點,父控件對于子控件的布局操作最好是放在layoutSubviews奶赔,因為只有在layoutSubviews這個方式里面才能保證子控件在你希望的地方顯示惋嚎。這個方法在控件最終顯示前會調(diào)用一次進(jìn)行最后的布局,當(dāng)然也不僅僅是這時候才調(diào)用站刑,附上layoutSubviews調(diào)用時機(jī).
1另伍、init初始化不會觸發(fā)layoutSubviews
2、addSubview會觸發(fā)layoutSubviews
3绞旅、設(shè)置view的Frame會觸發(fā)layoutSubviews摆尝,當(dāng)然前提是frame的值設(shè)置前后發(fā)生了變化
4、滾動一個UIScrollView會觸發(fā)layoutSubviews
5因悲、旋轉(zhuǎn)Screen會觸發(fā)父UIView上的layoutSubviews事件
6堕汞、改變一個UIView大小的時候也會觸發(fā)父UIView上的layoutSubviews事件
舉個例子,就拿本項目來說晃琳,CyclePictureCell的子控件有用于顯示圖片的imageVIew和用于顯示文字的UILabel臼朗,那么我對這兩個控件的大小以及位置的設(shè)置,最好放在CyclePictureCell的layoutSubviews方法蝎土。ps:layoutSubviews一定得調(diào)用super.layoutSubviews()
4.完成無限滾動
- 完成了無限滾動视哑,其思路說來就是讓我們顯示的cell"變多"。
假如我們有5張圖片,UICollectionView將會準(zhǔn)備用5個cell進(jìn)行顯示(當(dāng)然因為循環(huán)利用的機(jī)制在誊涯,所以創(chuàng)建出的cell并不一定是五個)挡毅。那么當(dāng)我們顯示到第五張圖片的時候,如果要繼續(xù)顯示那么暴构,應(yīng)該顯示第一張圖片跪呈。這時候如果強(qiáng)制的用UICollciontVIew的方法強(qiáng)制拉回第一個cell,會有一個非常難看的向左滑動的動畫取逾,而不是繼續(xù)向右滾動的動畫耗绿。
為了實現(xiàn)無限滾動,我只能把cell的數(shù)量變多砾隅,在五張圖片下误阻,我讓cell有500個或者更多,但是cell顯示的圖片卻還是只有我們設(shè)置的那五張晴埂。并且在第一次顯示的時候究反,讓顯示是cell是最中間的一張。這樣儒洛,就照成了無限循環(huán)的假象精耐。而且由于循環(huán)利用的機(jī)制的存在,是不用擔(dān)心效率問題的琅锻。
這里定時器的問題也需要額外注意一下卦停。反正要又這種意識向胡,只要用到了定時器就要擔(dān)心循環(huán)引用的問題。我的習(xí)慣是在開發(fā)的過程中惊完,把所有用到的控制器也好僵芹,自定義的view也好。我總會加上它的析構(gòu)方法deinit专执。
5.添加PageControl
- 這里我添加了UIPageControlPageControl控件。同樣值得注意的是它的frame應(yīng)該在ayoutSubviews里面設(shè)置郁油。
到達(dá)這一步本股,其實大概功能也都差不多了。而且代碼量也有300多行了桐腌。是可以考慮對代碼進(jìn)行整理了(其實是我實在不能忍了)拄显。
6整理代碼,重構(gòu)圖片存取方式
將UICollectionView的數(shù)據(jù)源和代理全部放進(jìn)了擴(kuò)展里面案站。這其實也是沒辦法的事情躬审,我總覺得讓一個View充當(dāng)數(shù)據(jù)源和代理是不符合思維邏輯的,但又找不到其他解決方式蟆盐,只要放進(jìn)擴(kuò)展承边。這樣讓CyclePictureView這個類的本體顯得沒那么臃腫
創(chuàng)建AuxiliaryModels.swift文件。加載怎樣的數(shù)據(jù)石挂,以及怎樣的加載數(shù)據(jù)應(yīng)該不是我們的CyclePictureView關(guān)心的事情博助。所以CyclePictureView的職責(zé)只要把圖片的數(shù)據(jù)源(url、名字)存儲起來痹愚,并在cell需要的時候給他就好富岳,至于怎么樣顯示加載,那是cell的事情拯腮。所以我利用ImageBox來存儲圖片的數(shù)據(jù)源窖式。這里不得不感嘆swift中枚舉的強(qiáng)大。然后在下一步中动壤,將感受到swift2.0中協(xié)議的強(qiáng)大萝喘。
7.添加pageControl對齊模式,并且將無限滾動功能變成協(xié)議
首先我是先對pageControl的功能進(jìn)行了一次增強(qiáng)琼懊,讓它的位置能夠被用戶所選擇蜒灰。于是我立即定義了一個枚舉PageControlAliment來表示能夠支持的對齊方式。剩下的操作無疑是在layoutSubviews中根據(jù)不同的枚舉計算不同的位置肩碟。
PageControlAlimentProtocol:本來完成對齊模式應(yīng)該分開一個工程再寫的强窖,請原諒這里我靈感來的太突然,停不下來了削祈。我的思路是這樣的:我是給pageControl添加了一個功能,然而這個功能對于CyclePictureView來說可以有也可以沒有翅溺。而且這個功能也不僅僅能夠用于CyclePictureView這個類脑漫,似乎是所有的擁有有UIPageControl這個控件的類(視圖),都可以有這個設(shè)置UIPageControl位置的功能咙崎。于是我想到了使用協(xié)議优幸。我要為這個功能設(shè)計一個協(xié)議,叫做PageControlAlimentProtocol褪猛,一個對齊協(xié)議网杆。任何一個View,你只要想方便的調(diào)整自己擁有UIPageControl伊滋,只要遵守這個協(xié)議碳却,協(xié)議便能夠幫你調(diào)節(jié)控件位置。于是協(xié)議我定義成這樣笑旺。
protocol PageControlAlimentProtocol: class{
var pageControlAliment: PageControlAliment {get set}
func AdjustPageControlPlace(pageControl: UIPageControl)
}
一個屬性昼浦,便是開始定義的位置類型的枚舉,要使用本協(xié)議筒主,必須得提供這個屬性关噪。還有協(xié)議一個方法,是調(diào)節(jié)位置的協(xié)議方法乌妙。這里我在協(xié)議的擴(kuò)展中給了它一個默認(rèn)的實現(xiàn)使兔。用戶在任何需要改變位置的代碼出直接調(diào)用即可。
- EndlessCycleProtocol:這個協(xié)議的思路和上面那個協(xié)議幾乎一樣藤韵。不過這個協(xié)議抽取出來感覺有點牽強(qiáng)火诸。不過代碼確實是簡潔了。這里希望大牛們能夠指點
8.進(jìn)一步改進(jìn)代碼荠察,并添加對storyboard的支持
- 首先是增加了CyclePictureView的代理協(xié)議CyclePictureViewDelegate置蜀,其實就是一個簡單的點擊事件的傳遞。
- 改進(jìn)了一些代碼的邏輯悉盆。
- 增加了對storyboard的支持盯荤,這里折騰了挺久,在從storyboard中加載的時候焕盟,不知道為什么會有莫名的偏移秋秤,找了好久才找到原因。
總結(jié)
在編碼過程中脚翘,我盡量多的使用swift的特性灼卢,代碼寫到第五步感覺和以前oc的思維都差不多。于是我強(qiáng)迫自己對代碼進(jìn)行修改来农。結(jié)果雖然是寫出來了不一樣的代碼鞋真,但是不知道有沒有過度重構(gòu),希望大家能夠指出不足之處沃于。當(dāng)然這個CyclePictureView圖片輪播器是可以拿到任何項目中去使用的涩咖。如果您發(fā)現(xiàn)任何BUG,或者有更好的建議或者意見海诲,歡迎您的指出。郵箱:wxl19950606@163.com.感謝您的支持檩互。