MJRefreshComponent.m 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // 代码地址: https://github.com/CoderMJLee/MJRefresh
  2. // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
  3. // MJRefreshComponent.m
  4. // MJRefreshExample
  5. //
  6. // Created by MJ Lee on 15/3/4.
  7. // Copyright (c) 2015年 小码哥. All rights reserved.
  8. //
  9. #import "MJRefreshComponent.h"
  10. #import "MJRefreshConst.h"
  11. #import "UIView+MJExtension.h"
  12. #import "UIScrollView+MJRefresh.h"
  13. @interface MJRefreshComponent()
  14. @property (strong, nonatomic) UIPanGestureRecognizer *pan;
  15. @end
  16. @implementation MJRefreshComponent
  17. #pragma mark - 初始化
  18. - (instancetype)initWithFrame:(CGRect)frame
  19. {
  20. if (self = [super initWithFrame:frame]) {
  21. // 准备工作
  22. [self prepare];
  23. // 默认是普通状态
  24. self.state = MJRefreshStateIdle;
  25. }
  26. return self;
  27. }
  28. - (void)prepare
  29. {
  30. // 基本属性
  31. self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  32. self.backgroundColor = [UIColor clearColor];
  33. }
  34. - (void)layoutSubviews
  35. {
  36. [super layoutSubviews];
  37. [self placeSubviews];
  38. }
  39. - (void)placeSubviews{}
  40. - (void)willMoveToSuperview:(UIView *)newSuperview
  41. {
  42. [super willMoveToSuperview:newSuperview];
  43. // 如果不是UIScrollView,不做任何事情
  44. if (newSuperview && ![newSuperview isKindOfClass:[UIScrollView class]]) return;
  45. // 旧的父控件移除监听
  46. [self removeObservers];
  47. if (newSuperview) { // 新的父控件
  48. // 设置宽度
  49. self.mj_w = newSuperview.mj_w;
  50. // 设置位置
  51. self.mj_x = 0;
  52. // 记录UIScrollView
  53. _scrollView = (UIScrollView *)newSuperview;
  54. // 设置永远支持垂直弹簧效果
  55. _scrollView.alwaysBounceVertical = YES;
  56. // 记录UIScrollView最开始的contentInset
  57. _scrollViewOriginalInset = _scrollView.contentInset;
  58. // 添加监听
  59. [self addObservers];
  60. }
  61. }
  62. - (void)drawRect:(CGRect)rect
  63. {
  64. [super drawRect:rect];
  65. if (self.state == MJRefreshStateWillRefresh) {
  66. // 预防view还没显示出来就调用了beginRefreshing
  67. self.state = MJRefreshStateRefreshing;
  68. }
  69. }
  70. #pragma mark - KVO监听
  71. - (void)addObservers
  72. {
  73. NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
  74. [self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentOffset options:options context:nil];
  75. [self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentSize options:options context:nil];
  76. self.pan = self.scrollView.panGestureRecognizer;
  77. [self.pan addObserver:self forKeyPath:MJRefreshKeyPathPanState options:options context:nil];
  78. }
  79. - (void)removeObservers
  80. {
  81. [self.superview removeObserver:self forKeyPath:MJRefreshKeyPathContentOffset];
  82. [self.superview removeObserver:self forKeyPath:MJRefreshKeyPathContentSize];;
  83. [self.pan removeObserver:self forKeyPath:MJRefreshKeyPathPanState];
  84. self.pan = nil;
  85. }
  86. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
  87. {
  88. // 遇到这些情况就直接返回
  89. if (!self.userInteractionEnabled) return;
  90. // 这个就算看不见也需要处理
  91. if ([keyPath isEqualToString:MJRefreshKeyPathContentSize]) {
  92. [self scrollViewContentSizeDidChange:change];
  93. }
  94. // 看不见
  95. if (self.hidden) return;
  96. if ([keyPath isEqualToString:MJRefreshKeyPathContentOffset]) {
  97. [self scrollViewContentOffsetDidChange:change];
  98. } else if ([keyPath isEqualToString:MJRefreshKeyPathPanState]) {
  99. [self scrollViewPanStateDidChange:change];
  100. }
  101. }
  102. - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change{}
  103. - (void)scrollViewContentSizeDidChange:(NSDictionary *)change{}
  104. - (void)scrollViewPanStateDidChange:(NSDictionary *)change{}
  105. #pragma mark - 公共方法
  106. #pragma mark 设置回调对象和回调方法
  107. - (void)setRefreshingTarget:(id)target refreshingAction:(SEL)action
  108. {
  109. self.refreshingTarget = target;
  110. self.refreshingAction = action;
  111. }
  112. #pragma mark 进入刷新状态
  113. - (void)beginRefreshing
  114. {
  115. [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
  116. self.alpha = 1.0;
  117. }];
  118. self.pullingPercent = 1.0;
  119. // 只要正在刷新,就完全显示
  120. if (self.window) {
  121. self.state = MJRefreshStateRefreshing;
  122. } else {
  123. // 预发当前正在刷新中时调用本方法使得header insert回置失败
  124. if (self.state != MJRefreshStateRefreshing) {
  125. self.state = MJRefreshStateWillRefresh;
  126. // 刷新(预防从另一个控制器回到这个控制器的情况,回来要重新刷新一下)
  127. [self setNeedsDisplay];
  128. }
  129. }
  130. }
  131. #pragma mark 结束刷新状态
  132. - (void)endRefreshing
  133. {
  134. self.state = MJRefreshStateIdle;
  135. }
  136. #pragma mark 是否正在刷新
  137. - (BOOL)isRefreshing
  138. {
  139. return self.state == MJRefreshStateRefreshing || self.state == MJRefreshStateWillRefresh;
  140. }
  141. #pragma mark 自动切换透明度
  142. - (void)setAutoChangeAlpha:(BOOL)autoChangeAlpha
  143. {
  144. self.automaticallyChangeAlpha = autoChangeAlpha;
  145. }
  146. - (BOOL)isAutoChangeAlpha
  147. {
  148. return self.isAutomaticallyChangeAlpha;
  149. }
  150. - (void)setAutomaticallyChangeAlpha:(BOOL)automaticallyChangeAlpha
  151. {
  152. _automaticallyChangeAlpha = automaticallyChangeAlpha;
  153. if (self.isRefreshing) return;
  154. if (automaticallyChangeAlpha) {
  155. self.alpha = self.pullingPercent;
  156. } else {
  157. self.alpha = 1.0;
  158. }
  159. }
  160. #pragma mark 根据拖拽进度设置透明度
  161. - (void)setPullingPercent:(CGFloat)pullingPercent
  162. {
  163. _pullingPercent = pullingPercent;
  164. if (self.isRefreshing) return;
  165. if (self.isAutomaticallyChangeAlpha) {
  166. self.alpha = pullingPercent;
  167. }
  168. }
  169. #pragma mark - 内部方法
  170. - (void)executeRefreshingCallback
  171. {
  172. dispatch_async(dispatch_get_main_queue(), ^{
  173. if (self.refreshingBlock) {
  174. self.refreshingBlock();
  175. }
  176. if ([self.refreshingTarget respondsToSelector:self.refreshingAction]) {
  177. MJRefreshMsgSend(MJRefreshMsgTarget(self.refreshingTarget), self.refreshingAction, self);
  178. }
  179. });
  180. }
  181. @end
  182. @implementation UILabel(MJRefresh)
  183. + (instancetype)label
  184. {
  185. UILabel *label = [[self alloc] init];
  186. label.font = MJRefreshLabelFont;
  187. label.textColor = MJRefreshLabelTextColor;
  188. label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  189. label.textAlignment = NSTextAlignmentCenter;
  190. label.backgroundColor = [UIColor clearColor];
  191. return label;
  192. }
  193. @end