MJRefresh源碼分析

MJRefresh源碼分析

  每次讀優秀的代碼都是一次深入的學習,每一次模仿,都是創造的開始!編程

——QQ 316045346 歡迎交流安全

1、MJRefresh源碼結構分析 

    MJRefresh主要爲UIScrollView,UITableView和UICollectionView添加頭部和尾部刷新控件。其主要由3大塊組成,類別工具,核心UIScrollView類別和頭部尾部刷新組件。以下圖:框架

2、工具類別

    上面示意圖中列出的幾個工具類別主要提供方便屬性訪問的功能。其主要是爲了方便MJRefresh庫本身的調用,固然你也能夠對它進行使用。函數

UIView+MJExtension類別提供了對UIView組件位置和尺寸的快速訪問方法,而且都支持快速獲取和設置:工具

@property (assign, nonatomic) CGFloat mj_x;
@property (assign, nonatomic) CGFloat mj_y;
@property (assign, nonatomic) CGFloat mj_w;
@property (assign, nonatomic) CGFloat mj_h;
@property (assign, nonatomic) CGSize mj_size;
@property (assign, nonatomic) CGPoint mj_origin;

UIScrollView+MJExtension提供了對UIScrollView的內容尺寸,偏移量等屬性的快速訪問:源碼分析

@property (readonly, nonatomic) UIEdgeInsets mj_inset;

@property (assign, nonatomic) CGFloat mj_insetT;
@property (assign, nonatomic) CGFloat mj_insetB;
@property (assign, nonatomic) CGFloat mj_insetL;
@property (assign, nonatomic) CGFloat mj_insetR;

@property (assign, nonatomic) CGFloat mj_offsetX;
@property (assign, nonatomic) CGFloat mj_offsetY;

@property (assign, nonatomic) CGFloat mj_contentW;
@property (assign, nonatomic) CGFloat mj_contentH;

NSBundle+MJRefresh這個類別提供對庫中資源的訪問方法:佈局

+ (instancetype)mj_refreshBundle;
//獲取箭頭圖片
+ (UIImage *)mj_arrowImage;
//獲取國際化字符串
+ (NSString *)mj_localizedStringForKey:(NSString *)key value:(NSString *)value;
+ (NSString *)mj_localizedStringForKey:(NSString *)key;

3、關於UIScrollView+MJRefresh

    這個類別是MJRefresh庫的核心,其中提供的mj_header和mj_footer兩個屬性用來添加頭部和尾部刷新組件。這兩個組件是做爲子視圖添加在UIScrollView上的,所以和UIScrollView的原生頭尾視圖都不影響。在之前版本的MJRefresh中,使用的是header和footer屬性,容易產生疑惑,所以後面版本框架中都添加了mj前綴。學習

    UIScrollView+MJRefresh類別在開發者設置mj_header和mj_footer屬性時,將這兩個組件添加爲當前滾動視圖的最下層子視圖,爲了知足某些自動加載的需求,這裏面有用runtime將UITableView和UICollectionView的reload函數進行替換,這樣作的目的是爲了在數據加載時統計界面的元素個數。動畫

4、刷新組件

    MJRefreshComponent是刷新組件的基類,其中定了一些通用方法。首先,MJRefresh庫的刷新組件核心思想是基於狀態的,即經過狀態來觸發某些組件行爲,例如正常的常態,下拉的pulling態,釋放的refreshing態等等。開發者除了能夠手動設置狀態外,主要經過監聽UIScrollView的偏移量等屬性來改變狀態。當UIScrollView有偏移量或內容尺寸的變化時,MJRefreshComponent會調用scrollViewContentOffsetDidChange函數,這個函數主要交給其子類實現。atom

    MJRefreshHeader類是頭部刷新組件的基類,其將刷新組件佈局在UIScrollView組件的頂部,而且封裝了記錄上次刷新時間的功能。MJRefreshStateHeader提供了接口供開發者設置不一樣狀態下刷新組件所顯示的文字,MJRefreshNormalHeader是一個更加上層的頭部刷新組件,其狀態文字是默認定義好的,而且支持國際化。MJRefreshGifHeader能夠支持顯示自定義刷新動畫,其能夠爲某個狀態設置一組圖片。

    尾部刷新組件的編寫邏輯和頭部刷新組件的編寫邏輯基本一致,MJRefresh中的尾部刷新組件分爲了兩類,一類是刷新完成後自動消失的,一類是自動刷新,刷新完成後不會自動消失,只是改變狀態。MFRefreshFooter與MJRefreshHeader的實現基本一致,MJRefreshBackFooter有刷新完成後自動還原的功能,MJRefreshBackNormalFooter是比較上層的封裝,其顯示默認的狀態文案,而且支持國際化。MJRefreshBackStateFooter則能夠手動設置不一樣狀態下刷新組件顯示的文字。MJRefreshBackGifFooter用來顯示自定義動畫的尾部刷新組件。MJRefreshAutoFooter是自動尾部刷新組件的基類,其能夠設置當尾部刷新組件出現多少比例時進行刷新(默認是徹底出現後進行刷新)。MJRefreshAutoStateFooter能夠自定義其各個狀態的文案。一樣,也有比較上層的MJRefreshAotuNormalFooter組件,這個組件封裝好了國際化的文案能夠直接使用,MJRefreshAutoGifFooter組件能夠顯示自定動畫的尾部刷新。

5、MJRefresh中的編程風格技巧與小亮點

1.複用,複用,再複用

    之因此看MJRefresh庫的代碼很是舒服,很大一部分源自其深刻的複用。首先MJRefreshComponent類抽象出了回調與刷新函數,而且提取出了須要子類複寫的通用的佈局、監聽等函數,讓子類的結構很是統一。MJRefreshHeader和MJRefreshFooter做爲頭部與尾部刷新組件的基類,抽象出了構造函數,而且實現了大部分組件與外部的佈局,邏輯動做等函數。再子類則專一與實現子類自身的UI與功能。還有一個小細節,也能夠看出MJRefresh對複用的追求,在setState函數的實現中,若是新的狀態與舊的狀態一致,則不須要作任何邏輯,全部的setState函數都須要這個邏輯,MJRefresh中採用的宏的方式進行替換,使代碼變得十分簡潔,示例以下:

#define MJRefreshCheckState \
MJRefreshState oldState = self.state; \
if (state == oldState) return; \
[super setState:state];


///////////
- (void)setState:(MJRefreshState)state
{
    MJRefreshCheckState
    
    // 設置狀態文字
    self.stateLabel.text = self.stateTitles[@(state)];
}

2.另外一種安全執行block的方式

    不少時候,咱們在執行block的時候都會先檢查下這個block是否爲nil,下面是咱們經常使用的代碼:

if (block) {
     block();
}

在MJRefresh中有使用問號冒號的方式來代替if語句,以下:

- (void)executeReloadDataBlock
{
    ! self.mj_reloadDataBlock ? : self.mj_reloadDataBlock(self.mj_totalDataCount);
}

這個表達式初看會有一些疑惑,其實?:的做用是返回一個值,若是?:前的表達式爲nil的話,則會返回?:後面的值,一樣,若是?:前面的表達式不爲nil的話,則直接返回,不會執行到後面的表達式,上面的寫法其實和第一種if語句的做用徹底一致。

相關文章
相關標籤/搜索