美文网首页
MJRefresh代码分析

MJRefresh代码分析

作者: 低吟浅唱1990 | 来源:发表于2015-11-04 11:08 被阅读3469次

    首先看看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动态添加属性

    这里添加了来那个属性,看看.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{}方法。

    相关文章

      网友评论

          本文标题:MJRefresh代码分析

          本文链接:https://www.haomeiwen.com/subject/rzgqhttx.html