MJRefresh代碼分析

首先看看MJRefrsh.h



#import"UIScrollView+MJRefresh.h"

#import"UIScrollView+MJExtension.h"

一般都是利用UIScrollView的偏移量來判斷刷新的, 在UIScrollView+MJRefresh.h中采用動態(tài)添加屬性的方法objc_setAssociatedObject()和objc_getAssociatedObject()函數(shù)給UIScrollView動態(tài)添加屬性MJRefreshHeader*header和MJRefreshFooter*footer;

一般情況下category里是不能添加屬性的,但是可用通過采用動態(tài)添加屬性的方法objc_setAssociatedObject()和objc_getAssociatedObject()函數(shù)給UIScrollView動態(tài)添加屬性

這里添加了來那個屬性,看看.m文件里的內(nèi)容


這樣就能夠?qū)傩耘cUIScrollView關(guān)聯(lián)


我們自己在給tableView添加上拉下拉刷新的時候需要為tableView添加header和footer

已給tableView添加MJRefreshNormalHeader類型的header為例:

_resuleTable.header= [MJRefreshNormalHeaderheaderWithRefreshingTarget:selfrefreshingAction:@selector(headerRefresh)];

MJRefreshNormalHeader里面沒有下面這個方法,但是他的父類MJRefreshHeader有這個方法。

+ (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action

+ (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action{

MJRefreshHeader*cmp = [[selfalloc]init];

[cmpsetRefreshingTarget:targetrefreshingAction:action];

returncmp;

}

然而在MJRefreshHeader并沒有-init 等構(gòu)造方法,在MJRefreshHeader的父類中MJRefreshComponent中有相應(yīng)

的構(gòu)造方法


MJRefreshComponent類是MJ這個第三方庫的一個基類,其他的header和footer都是繼承這個類

- (void)prepare?這里MJRefreshComponent實現(xiàn)的是控件的公共屬性,而一些特有的屬性在每個子類里實現(xiàn)

到這里就完成的UIView的生成,但是不確定他的大小和位置, ?盡管有回調(diào)的函數(shù),

_resuleTable.header 點語法條用了動態(tài)給UIScrollerView的屬性的getter 和setter方法

這里有 addSubview 方法的調(diào)用,接下來就會進入header的生命周期方法willMoveToSuperview,這個方法是在公共的基類MJRefreshComponent里實現(xiàn)的。因為這是基礎(chǔ)的行為,所以寫在公共的基類里,所有的子類都能共享:



在這個方法中設(shè)置了監(jiān)聽,監(jiān)聽UIScrollView的偏移量,

//設(shè)置永遠支持垂直彈簧效果

_scrollView.alwaysBounceVertical=YES; 保證了UIScrollView一只可以拉動。


#pragma mark - KVO監(jiān)聽

- (void)addObservers

{

NSKeyValueObservingOptionsoptions =NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld;

[self.scrollViewaddObserver:selfforKeyPath:MJRefreshKeyPathContentOffsetoptions:optionscontext:nil];

[self.scrollViewaddObserver:selfforKeyPath:MJRefreshKeyPathContentSizeoptions:optionscontext:nil];

self.pan=self.scrollView.panGestureRecognizer;

[self.panaddObserver:selfforKeyPath:MJRefreshKeyPathPanStateoptions:optionscontext:nil];

}

- (void)removeObservers

{

[self.superviewremoveObserver:selfforKeyPath:MJRefreshKeyPathContentOffset];

[self.superviewremoveObserver:selfforKeyPath:MJRefreshKeyPathContentSize];;

[self.panremoveObserver:selfforKeyPath:MJRefreshKeyPathPanState];

self.pan=nil;

}

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context

{

//遇到這些情況就直接返回

if(!self.userInteractionEnabled)return;

//這個就算看不見也需要處理

if([keyPathisEqualToString:MJRefreshKeyPathContentSize]) {

[selfscrollViewContentSizeDidChange:change];

}

//看不見

if(self.hidden)return;

if([keyPathisEqualToString:MJRefreshKeyPathContentOffset]) {

[selfscrollViewContentOffsetDidChange:change];

}elseif([keyPathisEqualToString:MJRefreshKeyPathPanState]) {

[selfscrollViewPanStateDidChange:change];

}

}

- (void)scrollViewContentOffsetDidChange:(NSDictionary*)change{}

- (void)scrollViewContentSizeDidChange:(NSDictionary*)change{}

- (void)scrollViewPanStateDidChange:(NSDictionary*)change{}

這里設(shè)置了三個監(jiān)聽,用于監(jiān)聽contentOffset、contentSize和state ?當值變化的時候在調(diào)用三個方法。

NSString*constMJRefreshKeyPathContentOffset =@"contentOffset";

NSString*constMJRefreshKeyPathContentInset =@"contentInset";

NSString*constMJRefreshKeyPathContentSize =@"contentSize";

NSString*constMJRefreshKeyPathPanState =@"state";

接下來會進入生命周期方法layoutSubviews:

- (void)layoutSubviews

{

[superlayoutSubviews];

[selfplaceSubviews];

}

- (void)placeSubviews{}

placeSubviews具體有子類實現(xiàn)。例如在MJRefreshHeader中得實現(xiàn)和

- (void)placeSubviews

{

[superplaceSubviews];

//設(shè)置y值(當自己的高度發(fā)生改變了,肯定要重新調(diào)整Y值,所以放到placeSubviews方法中設(shè)置y值)

self.mj_y= -self.mj_h-self.ignoredScrollViewContentInsetTop;

}

在MJRefreshNormalHeader中的具體實現(xiàn):

- (void)placeSubviews

{

[superplaceSubviews];

//箭頭

self.arrowView.mj_size=self.arrowView.image.size;

CGFloatarrowCenterX =self.mj_w*0.5;

if(!self.stateLabel.hidden) {

arrowCenterX -=100;

}

CGFloatarrowCenterY =self.mj_h*0.5;

self.arrowView.center=CGPointMake(arrowCenterX, arrowCenterY);

//圈圈

self.loadingView.frame=self.arrowView.frame;

}

實際下拉的時候會改變ContentOffset,從而觸發(fā)

- (void)scrollViewContentOffsetDidChange:(NSDictionary*)change{}方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容