先看一下源码目录结构:
1.Base
MJRefreshComponent:基类(继承至UIView)
```
/** 刷新控件的状态 */
typedefNS_ENUM(NSInteger, MJRefreshState) {
/** 普通闲置状态 */
MJRefreshStateIdle =1,
/** 松开就可以进行刷新的状态 */
MJRefreshStatePulling,
/** 正在刷新中的状态 */
MJRefreshStateRefreshing,
/** 即将刷新的状态 */
MJRefreshStateWillRefresh,
/** 所有数据加载完毕,没有更多的数据了 */
MJRefreshStateNoMoreData
};
```
定义的三种状态的回调block
```
/** 进入刷新状态的回调 */
typedef void (^MJRefreshComponentRefreshingBlock)(void);
/** 开始刷新后的回调(进入刷新状态后的回调) */
typedef void (^MJRefreshComponentbeginRefreshingCompletionBlock)(void);
/** 结束刷新后的回调 */
typedef void (^MJRefreshComponentEndRefreshingCompletionBlock)(void);
#pragma mark - 交给子类们去实现()
/** 初始化 */
- (void)prepare NS_REQUIRES_SUPER;//这里可以自定义控件或者设置GIF图片(初始化的时候调用)
/** 摆放子控件frame */
- (void)placeSubviews NS_REQUIRES_SUPER;//这里做布局(layoutSubviews时调用)
/** 当scrollView的contentOffset发生改变的时候调用 */
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change NS_REQUIRES_SUPER;
/** 当scrollView的contentSize发生改变的时候调用 */
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change NS_REQUIRES_SUPER;
/** 当scrollView的拖拽状态发生改变的时候调用 */
- (void)scrollViewPanStateDidChange:(NSDictionary *)change NS_REQUIRES_SUPER;
```
Header
MJRefreshHeader,MJRefreshStateHeader,MJRefreshNormalHeader,MJRefreshGifHeader
Footer(分为back和auto:是否自动刷新,尾部跟随)
UIScrollView分类:给UIScrollView添加一个控件(header,footer)
```
- (void)setMj_header:(MJRefreshHeader *)mj_header
{
if (mj_header != self.mj_header) {
// 删除旧的,添加新的
[self.mj_header removeFromSuperview];
[self insertSubview:mj_header atIndex:0];
// 存储新的
objc_setAssociatedObject(self, &MJRefreshHeaderKey,
mj_header, OBJC_ASSOCIATION_RETAIN);//runtime给对象绑定属性
}
}
- (MJRefreshHeader *)mj_header
{
return objc_getAssociatedObject(self, &MJRefreshHeaderKey);//runtime获取属性
}
```
footer也是类似
原理:
1.通过UIScrollView分类:给UIScrollView添加一个控件(header,footer)
2.header和footer定义回调block,获取到父控件UIScrollView
3.header和footer通过KVO,观察父控件UIScrollView的offset,contentSize
[self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentOffset options:options context:nil];
[self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentSize options:options context:nil];
4.根据偏移量去做相关的操作(UI显示和触发回调block)
5.完成观察,刷新完成
自定义:可以在初始化重写prepare方法,自定义样式