关于MJRefresh的源码

MJRefresh 是 OC 语言里面算是一款比较通用的刷新框架了,可以用于 UITableView 和 UICollectionView 的刷新,从而可以很方便的完成下拉刷新和上拉加载更多。而且可定制程度也很高。

最近需要在公司的项目上加入一个刷新的特效,而公司项目用的刷新框架是 MJefresh ,所以在完成需求的同时就顺便把 MJRefresh 框架的源码给看了一遍。然后写下这篇文章总结一下。

MJRefresh框架的结构是用子类继承的方式实现的,创建一个基类MJRefreshComponent,然后通过继承的方式,让MJRefreshHeader和MJRefreshFooter分别具备下拉刷新和上拉加载的功能。从继承机构来看可以分为三层,具体的继承关系可以从下面的图里看:

关于MJRefresh的源码_第1张图片

其中五大核心类库

MJRefreshComponent

MJRefreshHeader

MJRefreshFooter

MJRefreshBackFooter

MJRefreshAutoFooter

其它的类都是在上面的基础上自定义的类。

首先来看一下MJRefresh框架的基类:MJRefreshComponent

MJRefreshComponent

这个类作为框架的基类,涵盖了基类所具备的状态,回调block等,完成了以下几件事情:

布局控件的位置。

完成基本的设置工作。

设置下拉刷新时的文本框。

设置控件的所有状态。

设置回调函数。

添加监听。

提供刷新,停止刷新接口。

提供子类需要实现的方法。

具体实现:

定义控件的全部的状态

关于MJRefresh的源码_第2张图片

定义控件的回调函数

Target-Action类型的回调

监听函数的实现

关于MJRefresh的源码_第3张图片

开始刷新和停止刷新

关于MJRefresh的源码_第4张图片

需要子类实现的方法

关于MJRefresh的源码_第5张图片

其中代码中作者的注解可以看出框架具体的操作对象是 scrollView 而不是具体的 tableView 和 collectionView

其中如果该类是 scrollView 或者 scrollView 子类就对其添加监听。

其中isKindOfClass和isMemberOfClass的区别是需要关注的。

关于MJRefresh的源码_第6张图片

然后MJRefreshHeader和MJRefreshFooter都继承MJRefreshComponent实现。

MJRefreshHeader

MJRefreshHeader继承MJRefreshComponent,它做了这几件事:

初始化。

设置header高度。

重新计算下拉高度值。

记录上一次刷新时间或者是第一次刷新时间。

由contentOffset的变化,来切换状态(默认状态,可以刷新的状态,正在刷新的状态),实现方法是:scrollViewContentOffsetDidChange:。

在切换状态时,执行相应的操作。实现方法是:setState:。

两种创建方式(两种构造方法)

关于MJRefresh的源码_第7张图片

重写父类方法,设置Y值 ,同时设置上次刷新时间

关于MJRefresh的源码_第8张图片

状态切换

关于MJRefresh的源码_第9张图片

重写控件所有状态的set方法,设置

关于MJRefresh的源码_第10张图片

MJRefreshStateHeader

这个类是MJRefreshHeader类的子类,它做了两件事:

设置stateLabel和lastUpdatedTimeLabel的位置。

根据控件状态的切换(默认状态,正在刷新状态),实现了这两个label显示的文字的切换。

这里设置文字的方法有点儿类似按钮。将每一个状态对应的提示文字放入一个字典里面,key是状态的NSNumber形式。

关于MJRefresh的源码_第11张图片
关于MJRefresh的源码_第12张图片

布局方法

关于MJRefresh的源码_第13张图片

重写set方法,更新刷新时间

关于MJRefresh的源码_第14张图片

1.作者通过使用block来让用户自己定义日期现实的格式,如果用户没有自定义,就使用作者提供的默认格式。

2.默认格式的设置里,判断了是否是今日,是否是今年的情况。由具体时间显示label的文字是否显示年,月,日。

MJRefreshNormalHeader

MJRefreshNormalHeader 继承 MJRefreshStateHeader,它主要做了两件事:

它在MJRefreshStateHeader上添加了_arrowView和loadingView。

布局了这两个view并在Refresh控件的状态切换的时候改变这两个view的样式。

作者同样是通过重写父类的三个方法实现子类自定义本类的控件。

关于MJRefresh的源码_第15张图片
关于MJRefresh的源码_第16张图片

到此为止,我们已经从MJRefreshComponent到MJRefreshNormalHeader的实现过程看了一遍。可以看出,作者将prepare,placeSubviews以及setState:方法作为基类的方法,让下面的子类去一层一层实现。

而每一层的子类,根据自身的职责,分别按照自己的方式来实现这三个方法:

MJRefreshHeader: 负责header的高度和调整header自身在外部的位置。

MJRefreshStateHeader:负责header内部的stateLabel和lastUpdatedTimeLabel的布局和不同状态下内部文字的显示。

MJRefreshNormalHeader:负责header内部的loadingView以及arrowView的布局和不同状态下的显示。

这样做的好处是,如果想要增加某种类型的header,只要在某一层上做文章即可。例如该框架里的MJRefreshGifHeader,它和MJRefreshNormalHeader属于同一级,都是继承于MJRefreshStateHeader。因为二者都具有相同形式的stateLabel和lastUpdatedTimeLabel,唯一不同的就是左侧的部分:

MJRefreshNormalHeader的左侧是箭头。

MJRefreshGifHeader的左侧则是一个gif动画。

关于两种footerView的区别。

BackFooter 自动弹回底部

backFooter 是上拉出现加载 view ,然后在加载完以后就这个 view 就自动弹回底部的。即使是 tableView 或者是 collectionView 当数据量还不足以填充满整个界面的时候也是如此的。

Auto Footer 自动刷新

自动刷新方式是没有明显的上拉的动作,就是当滑动到最底部的时候,就自动加载。而当 tableView 或者 collectionView 的数据不足以填充满这个屏幕的时候,刷新的 view 也是现实在 最后一个数据项的下面一项。然后点击加载更多。

总体而言,这个框架是在最基类里面实现了最基本的流程,而每个流程怎么处理则因为 header 和 Footer 的不同需要不同的逻辑处理。所以有 header 和 Footer 的子类。

但是由于 Footer 的上拉有两种样式和情况,所以在 Footer 的基础上又实现两个类 backFooter 和 autoFooter 。

你可能感兴趣的:(关于MJRefresh的源码)