手把手教會自定義下拉重新整理控制元件

dearqjn發表於2016-11-13

一:前言

記得工作中第一次用的重新整理控制元件是svpulltorefresh,用法稍微有點麻煩,而且bug頗多,後來果斷放棄,現在用的是MJRefresh,不管是用法還是bug,都比前一個好多了,但是不久前也遇到了一個致命的bug,有好些情況下會導致MJRefresh陷入一個死迴圈,導致不斷的重新整理,只能重啟軟體才行。MJRefresh工程比較龐大,找到了bug也很難修改,然後還是決定自己寫一個,系統提供的UIRefreshControl我認為是最好的,缺點是不提供自定義UI的方法,那麼我就自己基於它來自定義UI。我不是一開始就決定繼承於UIRefreshControl,我同時也寫了一個繼承與UIView的control,兩個進行對比,發現使用UIview會有很多弊端,這種弊端在一些複雜特殊的情況下一下子就暴露出來了,而且很難解決,當然,正常狀態下是沒什麼問題的,有興趣的同學倒是可以去試一試。本demo供大家學習和參考,如有發現bug,還請issues 我。

二: 瞭解 UIRefreshControl

  • 基本使用方法

  • 存在的問題
      1. 重新整理時的動畫是一個灰色小菊花,很多情況下不符合app的重新整理動畫效果
      1. 經過多次反覆測試,下拉的偏移量達到130以上才會觸發重新整理方法,很顯然這個也不符合,一般的重新整理控制元件的高度60左右,所以下拉的偏移量達到60就可以觸發重新整理的方法了。
  • 自定義控制元件的思路
      1. 去掉預設的動畫效果
      1. 自定義自己的動畫效果
      1. 改變滿足重新整理時的條件

三:FMRefreshControl

  • 先看一下我寫完的這個控制元件的使用方法

兩行程式碼,用法比系統的還要稍微簡單一點。

  • 再看一下效果
1a0141ae9e896

四:思路與程式碼

1. 關於 UIRefreshControl 的幾個注意點,通過frame無法修改它的高度,修改高度目前只找到一種方法,先新增到 superViwe,再執行

一開始我是想改變它的高度是否就能改變它的觸發重新整理的偏移量,然後我找到了這個方法可以修改它的高度,但實際上改變了高度還是無法改變觸發下拉重新整理的偏移量,所以我們需要自定義去觸發重新整理這個動作的時機。

2.手動去觸發重新整理動作也有幾個注意點,我們是根據偏移量去觸發重新整理,但是僅僅靠這一個動作是不夠的,還需要一個條件,那就是使用者手指響應過螢幕,簡單地說,先定義一個變數,如果使用者觸控過螢幕,就把變數置為YES,然後再判斷使用者手指離開時是否達到了觸發重新整理的偏移量,如果兩個條件都滿足,就觸發重新整理,重新整理完把變數置為NO,如果不滿足,就不觸發,也把變數置為NO。這樣就避免了UIScrollow 因偏移量變動而導致非人為的重新整理。

3. 進入程式碼階段

初始化的時候賦一個 target 和 一個 action,當滿足條件的時候,我們需要知道讓誰去執行重新整理方法,有這兩個引數足夠,當執行到第二行 addSubView的時候,我們需要在control內部實現這個方法:

這樣,我們就知道當前這個control被新增到哪個父檢視上了,為了安全及程式碼的嚴謹,先判斷父檢視是否屬於
UIScrollView,如果是,就用KVO監聽contentOffset屬性,這樣便能知道使用者滑動的偏移量。

這裡我定義了3種狀態:

以及切換狀態後UI的切換和方法的觸發:

切換到FMRefreshStateNormal 停止動畫,切換到FMRefreshStatePulling 開始動畫,達到這個狀態,說明使用者已經達到了重新整理的偏移量,此時鬆手便可重新整理,切換到FMRefreshStateRefreshing,如果此時往回滑動,小於臨界值,那麼狀態重新切回FMRefreshStateNormal
滿足重新整理條件,則便可執行以下方法:

下面看最關鍵的KVO方法,也是這裡面最複雜的邏輯處理程式碼:

這裡最重要的就是處理兩點:1. 根據偏移量和使用者手指的拖動來切換狀態,2. control上面的子檢視需要我們根據偏移量來實時更新。

還有一種情況,上面也提到過,使用者先滑動到FMRefreshStatePulling狀態,然後又往回滑動,此時的偏移量在0-FMRefreshStatePulling狀態的偏移量之間,此時呼叫自身的 endRefreshing偏移量不會復原,還需要我們自己處理,看了幾個老外寫的自定義重新整理控制元件,他們都沒修復這個bug。他們也沒封裝,全部程式碼寫在了控制器裡,什麼都沒有改變,只是實現了一個動畫效果,還多了個bug,動畫效果倒是不錯的。有興趣的可以參考一番:
https://www.jackrabbitmobile.com/app-development/ios-custom-pull-to-refresh-contro/
https://possiblemobile.com/2014/05/ios-custom-pull-to-refresh/

最後還有一點不要忘記 dealloc移除監聽:

整篇文章從上至下是按照整個完整的思路寫下來的,先是提出遇到的問題以及難點,然後最後的程式碼和思路也是由外至內一路寫下來,希望方便大家閱讀。這是上篇,下拉重新整理的,還有下篇,上拉載入,過兩天寫,demo中已經有了,不過就是還沒優化。

domo地址:https://github.com/suifengqjn/FMRefreshControl

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

手把手教會自定義下拉重新整理控制元件 手把手教會自定義下拉重新整理控制元件

相關文章