iOS開發之三個Button實現圖片無限輪播(參考手機淘寶,Swift版)

這兩天使用Reveal工具查看"手機淘寶"App的UI層次時,發現其圖片輪播使用了三個UIButton的複用來實現的圖片循環無縫滾動。因而乎就有了今天這篇博客,看到「手機淘寶」這個幻燈片的UI層級時,就想要動手使用三個Button來實現一下,固然本篇博客使用是Swift語言,思路就是使用三個Button進行圖片無限輪播。以前發過兩篇關於圖片輪播的博客,一個是沒有使用ImageView複用的,一個是使用兩張ImageView進行復用來實現圖片輪播的,都是使用的Objective-C實現的,並在github上進行了代碼分享。html

本篇博客就是介紹如何去一步步的封裝這個三個Button的無限輪播的組件的。在實現時將該無限輪播的組件進行了封裝,須要你在實例化該組件後,傳入一個存放圖片地址的數組,數組中能夠是本地圖片的名字,也能夠是一個網絡圖片的地址。若是是網絡圖片的地址,組件中會使用NSRULSession並採用合適的緩存策略從網絡加載圖片,加載完後在咱們的組件上進行顯示。廢話少說,進入咱們今天的主題。git

今天的博客徹底是我的興趣愛好,也不是公司中項目要使用的緣故纔去實現的。就是看到了淘寶中的輪播圖,從UI層級上感受這樣能夠實現,因而乎就打開Xcode,建立個Swift工程實現一把,過程仍是蠻愉快的。固然今天封裝組件的名稱是以公司的名稱首字母作的前綴了,這也便於在之後的工做中遇到該問題直接拿過來就用呢。github

 

1、對「手機淘寶」UI層次的簡單分析數組

下方截圖就是當時我用Reveal工具查看的手機淘寶App的UI層級,下方只是幻燈片的部分。下方整個頁面是使用UICollectionView來實現的了,下方的幻燈片所在的UIScrollView就放在UICollectionView上的一個Cell上。固然這不是咱們今天的重點,咱們將目光轉移到左邊紅框中的數學層級上。能夠明顯的看出UIScrollView上貼了三個UIButton,而每一個UIButton上又貼了一個UIImageView緩存

須要注意的一點是你看到UIButton是三個Button的中間一個,從下面UI視圖中咱們不難分析出,不管當前顯示的是第幾張圖片,你看到的永遠是中間Button上顯示的圖片。也就是將要顯示的圖片放到中間的Button上,左邊的Button存放上一張圖片,右邊的Button存放下一張圖片。當用戶左劃或者右劃後,咱們要作的事情就是將中間按鈕放到可視區,而且設置成要顯示的圖片,固然左右兩個Button都得設置成相應的圖片,便於用戶下次移動。固然這只是個人我的猜想,上面這種思路使用代碼來實現是徹底可行的,而且能夠實現無循環無縫滾動了。網絡

固然,上面說的原理比較簡單,具體使用代碼實現起來仍是須要許多細節的。好比用戶滑動時定時器的掛起和喚醒,用戶左右滑動方向的記錄,便於自動輪播時的方向與用戶上次滑動的方向一致,異步加載網絡請求圖片,加載後顯示在相應的Button上,經過Closure回調出用戶點擊事件可當前圖片的索引信息等等須要注意的細節。敲代碼也有幾年時間了,有一點感觸挺深的就是「說和作」徹底是兩碼事,也就是你有思路和你把你的思路用代碼實現,這是徹底不一樣的概念。固然正確的思路當然重要,可是不去實現再好的思路也是枉費,實踐出真知嗎。說這麼多,有回到了說與作的問題上,這話題就很少討論了,高執行力,高自制力好處是多多的。言歸正傳,回到今天的主題。閉包

  

 

2、從「原理圖」中來看今天輪播的主題異步

下方就是今天要實現的輪播組件的原理圖,思路就是這麼個思路,要實現起來還得靠代碼往上摞呢。下方解析圖是以輪播5張圖片爲例。初始化狀態是你看到的是第一張圖片,第一張圖片位於三個Button的中間,而後左邊就是最後一張圖片,右邊是第二張圖片。若是用戶想右滑動顯示的第二張圖片(對應着下方的第一步),當第二張圖片已經徹底顯示出來後,咱們要作的第一件事情就是將用戶移動的位置進行復位,也就是將第二個Button移動到顯示的位置,而後設置按鈕上顯示相應的圖片。第一個按鈕就顯示當前圖片的前一張圖片,若是當前顯示的是第一張圖片,那麼第一個按鈕上就顯示最後一張圖片。第三個按鈕就顯示當前圖片的下一張圖片,若是當前顯示的圖片是最後一張圖片的話,那麼第三個按鈕上就顯示第一張圖片。這樣就能夠圖片輪播了。函數

  

 

3、該自定義控件的視圖層級工具

下圖就是咱們按照上面的思路,使用ScrollView上添加3個Button來實現的圖片輪播,無縫滾動的效果仍是蠻OK的。在下方運行效果中美女圖片是從本地加載的,而風景圖片是使用NSURLSession和GCD的東西並行異步的從網絡獲取的,獲取完後再加載到相應Button的ImageView上。下方就是咱們本篇博客相關Demo的運行效果,單從效果上來看,與以前所發佈的圖片輪播沒有什麼區別,可是其內部實現機制仍是有較大區別的。接下來就逐步的看一下代碼實現。

  

上面是運行效果,下方是UI的層級。固然也是用咱們強大的Reveal來查看的了,下方紅框中就是咱們圖片輪播的視圖層級。該視圖層級與「手機淘寶」上是一致的,都是在UIScrollView上貼了三個Button,而後在每一個Button上貼了一個ImageView。層級比較簡單,而你看到的固然是中間Button上的ImageView了,更多細節請看下圖。

  

 

4、代碼實現

運行效果看完了,UI層級結構也看完了,那麼接下來就到了咱們代碼實現的時刻了。下方從組件的調用方式入手,逐步的去看一下上述效果是如何實現的。

1.上述組件的調用方式

下方代碼段就是上述組件的實例化和調用方式,首先進行初始化,而後將該組件添加到父視圖上。以後將要顯示的圖片數組imagesNameArray傳入組件中,最後設置一下組件的閉包回調便可,該回調將每一個按鈕點擊的時間回調給組件的使用者,該Closure的參數是當前點擊按鈕上所顯示的Image的索引,說白了也就是你當前點擊的第幾張圖片。

  

在調用組件時,傳入給組件的參數是一個數組,下方代碼就是咱們初始化imagesNameArray的函數。從該代碼段中咱們不難看出,該數組中存儲的有本地圖片的名字,也有UIImage的對象,也有網絡圖片的URL。將含有三種元素的數組傳給咱們的組件實例,這些數組中的資源就能夠按照數組中的順序依次的循環輪播了。

  

 

2.上述組件的核心代碼

組件調用方式仍是蠻簡單的,看完調用方式,接下來來看一下具體的代碼實現。下方是咱們組件中比較核心的實現部分。

(1).異步加載網絡圖片

下方代碼段就是遍歷咱們的ImagesNameArray,找出該數組中全部的網絡圖片的URL,每找到一個URL就開啓一個線程來請求該地址中的圖片。下方的queue是並行隊列,此處固然是並行隊列的異步執行了。關於GCD的東西,請參考以前的博客《Grand Central Dispatch詳解》。

  

下方代碼段就是requestImage()方法中的內容了,該方法中使用NSSession並配置相應的緩存策略來請求網絡圖片。加載完圖片後,將ImagesNameArray中相應的URL替換成相應的UIImage對象,而後在主線程中更新UI顯示相應的圖片,具體代碼以下所示。

  

 

(2)moveImageView()方法的實現

該方法負責將按鈕歸位與賦值,該方法對應着上述原理圖的第二和第三步。上面網絡請求完一張圖片後就會調用該方法更新UI。該方法的具體實現以下所示。下方代碼中首先獲取當前顯示的頁數,也就是當前顯示的Image的索引,而後將第二個Button移動到可視區,最後調用setButtonImage()函數將每一個Button上的ImageView設置成相應的Image。

  

 

(3)、定時器的實現

圖片要隔段時間自動輪播,此處咱們使用的是dispatch_source中的定時器類型來實現的自動輪播。下方就是咱們定時器的實現,以下所示,代碼比較簡單,在此就不作過多的贅述了,建立完定時器咱們不要忘了對定時器的source進行喚醒便可。

  

當用戶進行手動切換時,咱們要對定時器進行相應的掛起和喚醒操做。也就是說當用戶開始滑動時咱們要對定時器進行掛起,當用戶滑動結束後要對定時器進行喚醒。固然這些都是在ScrollView相應的代理方法中進行處理的,具體以下所示:

  

 

(4)、滑動結束後更新按鈕的位置和圖片

不管是手動滑動,仍是使用定時器滑動,滑動結束後咱們都須要更新一下按鈕的位置和按鈕上要顯示的圖片。因此咱們還須要使用到UIScrollView上的一個代理方法,那就是scrollViewDidScroll(),在該代理方法中咱們調用了moveImage()方法來更新Button的位置和Button上ImageView要顯示的圖片信息。沒有這個方法,圖片就動不起來了,具體代碼以下所示:

  

 

上述是該Demo的核心代碼,更爲詳細的代碼請移步於github: https://github.com/lizelu/CEImagesScrollDisplay, 因本篇博客篇幅有限,更具體的細節在此就不作過多贅述了,Demo已在上述github上進行分享。

相關文章
相關標籤/搜索