MJRefresh代码分析

http://www.jianshu.com/p/fc1ca1acc12e

首先看看MJRefrsh.h



#import"UIScrollView+MJRefresh.h"

#import"UIScrollView+MJExtension.h"

一般都是利用UIScrollView的偏移量来判断刷新的, 在UIScrollView+MJRefresh.h中采用动态添加属性的方法objc_setAssociatedObject()和objc_getAssociatedObject()函数给UIScrollView动态添加属性MJRefreshHeader*header和MJRefreshFooter*footer;

一般情况下category里是不能添加属性的,但是可用通过采用动态添加属性的方法objc_setAssociatedObject()和objc_getAssociatedObject()函数给UIScrollView动态添加属性

MJRefresh代码分析_第1张图片

这里添加了来那个属性,看看.m文件里的内容



这样就能够属性与UIScrollView关联

我们自己在给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 等构造方法,在MJRefreshHeader的父类中MJRefreshComponent中有相应

的构造方法



MJRefreshComponent类是MJ这个第三方库的一个基类,其他的header和footer都是继承这个类

- (void)prepare 这里MJRefreshComponent实现的是控件的公共属性,而一些特有的属性在每个子类里实现

到这里就完成的UIView的生成,但是不确定他的大小和位置,  尽管有回调的函数,

_resuleTable.header 点语法条用了动态给UIScrollerView的属性的getter 和setter方法

这里有 addSubview 方法的调用,接下来就会进入header的生命周期方法willMoveToSuperview,这个方法是在公共的基类MJRefreshComponent里实现的。因为这是基础的行为,所以写在公共的基类里,所有的子类都能共享:



在这个方法中设置了监听,监听UIScrollView的偏移量,

//设置永远支持垂直弹簧效果

_scrollView.alwaysBounceVertical=YES; 保证了UIScrollView一只可以拉动。

#pragma mark - KVO监听

- (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{}

这里设置了三个监听,用于监听contentOffset、contentSize和state  当值变化的时候在调用三个方法。

NSString*constMJRefreshKeyPathContentOffset =@"contentOffset";

NSString*constMJRefreshKeyPathContentInset =@"contentInset";

NSString*constMJRefreshKeyPathContentSize =@"contentSize";

NSString*constMJRefreshKeyPathPanState =@"state";

接下来会进入生命周期方法layoutSubviews:

- (void)layoutSubviews

{

[superlayoutSubviews];

[selfplaceSubviews];

}

- (void)placeSubviews{}

placeSubviews具体有子类实现。例如在MJRefreshHeader中得实现和

- (void)placeSubviews

{

[superplaceSubviews];

//设置y值(当自己的高度发生改变了,肯定要重新调整Y值,所以放到placeSubviews方法中设置y值)

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

}

在MJRefreshNormalHeader中的具体实现:

- (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,从而触发

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



文/低吟浅唱1990(简书作者)
原文链接:http://www.jianshu.com/p/fc1ca1acc12e
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

你可能感兴趣的:(MJRefresh代码分析)