MJRefreshComponent.m 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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 "Aspects.h"
  12. @interface MJRefreshComponent()
  13. @property (strong, nonatomic) UIPanGestureRecognizer *pan;
  14. @end
  15. @implementation MJRefreshComponent
  16. #pragma mark - 初始化
  17. - (instancetype)initWithFrame:(CGRect)frame
  18. {
  19. if (self = [super initWithFrame:frame]) {
  20. // 准备工作
  21. [self prepare];
  22. // 默认是普通状态
  23. self.state = MJRefreshStateIdle;
  24. }
  25. return self;
  26. }
  27. - (void)prepare
  28. {
  29. // 基本属性
  30. self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  31. self.backgroundColor = [UIColor clearColor];
  32. }
  33. - (void)layoutSubviews
  34. {
  35. [self placeSubviews];
  36. [super layoutSubviews];
  37. }
  38. - (void)placeSubviews{}
  39. - (void)willMoveToSuperview:(UIView *)newSuperview
  40. {
  41. [super willMoveToSuperview:newSuperview];
  42. // 如果不是UIScrollView,不做任何事情
  43. if (newSuperview && ![newSuperview isKindOfClass:[UIScrollView class]]) return;
  44. // 旧的父控件移除监听
  45. [self removeObservers];
  46. if (newSuperview) { // 新的父控件
  47. // 设置宽度
  48. self.mj_w = newSuperview.mj_w;
  49. // 设置位置
  50. self.mj_x = -_scrollView.mj_insetL;
  51. // 记录UIScrollView
  52. _scrollView = (UIScrollView *)newSuperview;
  53. // 设置永远支持垂直弹簧效果
  54. _scrollView.alwaysBounceVertical = YES;
  55. // 记录UIScrollView最开始的contentInset
  56. _scrollViewOriginalInset = _scrollView.mj_inset;
  57. // 添加监听
  58. [self addObservers];
  59. }
  60. }
  61. - (void)drawRect:(CGRect)rect
  62. {
  63. [super drawRect:rect];
  64. if (self.state == MJRefreshStateWillRefresh) {
  65. // 预防view还没显示出来就调用了beginRefreshing
  66. self.state = MJRefreshStateRefreshing;
  67. }
  68. }
  69. #pragma mark - KVO监听
  70. - (void)addObservers
  71. {
  72. NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
  73. [self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentOffset options:options context:nil];
  74. [self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentSize options:options context:nil];
  75. self.pan = self.scrollView.panGestureRecognizer;
  76. [self.pan addObserver:self forKeyPath:MJRefreshKeyPathPanState options:options context:nil];
  77. }
  78. - (void)removeObservers
  79. {
  80. [self.superview removeObserver:self forKeyPath:MJRefreshKeyPathContentOffset];
  81. [self.superview removeObserver:self forKeyPath:MJRefreshKeyPathContentSize];
  82. [self.pan removeObserver:self forKeyPath:MJRefreshKeyPathPanState];
  83. self.pan = nil;
  84. }
  85. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
  86. {
  87. // 遇到这些情况就直接返回
  88. if (!self.userInteractionEnabled) return;
  89. // 这个就算看不见也需要处理
  90. if ([keyPath isEqualToString:MJRefreshKeyPathContentSize]) {
  91. [self scrollViewContentSizeDidChange:change];
  92. }
  93. // 看不见
  94. if (self.hidden) return;
  95. if ([keyPath isEqualToString:MJRefreshKeyPathContentOffset]) {
  96. [self scrollViewContentOffsetDidChange:change];
  97. } else if ([keyPath isEqualToString:MJRefreshKeyPathPanState]) {
  98. [self scrollViewPanStateDidChange:change];
  99. }
  100. }
  101. - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change{}
  102. - (void)scrollViewContentSizeDidChange:(NSDictionary *)change{}
  103. - (void)scrollViewPanStateDidChange:(NSDictionary *)change{}
  104. #pragma mark - 公共方法
  105. #pragma mark 设置回调对象和回调方法
  106. - (void)setRefreshingTarget:(id)target refreshingAction:(SEL)action
  107. {
  108. self.refreshingTarget = target;
  109. self.refreshingAction = action;
  110. }
  111. - (void)setState:(MJRefreshState)state
  112. {
  113. _state = state;
  114. // 加入主队列的目的是等setState:方法调用完毕、设置完文字后再去布局子控件
  115. MJRefreshDispatchAsyncOnMainQueue([self setNeedsLayout];)
  116. }
  117. #pragma mark 进入刷新状态
  118. - (void)beginRefreshing
  119. {
  120. [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
  121. self.alpha = 1.0;
  122. }];
  123. self.pullingPercent = 1.0;
  124. // 只要正在刷新,就完全显示
  125. if (self.window) {
  126. self.state = MJRefreshStateRefreshing;
  127. } else {
  128. // 预防正在刷新中时,调用本方法使得header inset回置失败
  129. if (self.state != MJRefreshStateRefreshing) {
  130. self.state = MJRefreshStateWillRefresh;
  131. // 刷新(预防从另一个控制器回到这个控制器的情况,回来要重新刷新一下)
  132. [self setNeedsDisplay];
  133. }
  134. }
  135. }
  136. - (void)beginRefreshingWithCompletionBlock:(void (^)(void))completionBlock
  137. {
  138. self.beginRefreshingCompletionBlock = completionBlock;
  139. [self beginRefreshing];
  140. }
  141. #pragma mark 结束刷新状态
  142. - (void)endRefreshing
  143. {
  144. MJRefreshDispatchAsyncOnMainQueue(self.state = MJRefreshStateIdle;)
  145. }
  146. - (void)endRefreshingWithCompletionBlock:(void (^)(void))completionBlock
  147. {
  148. self.endRefreshingCompletionBlock = completionBlock;
  149. [self endRefreshing];
  150. }
  151. /// <#Description#>
  152. -(void)aspectsEndRefreshing:(void (^)(void))block{
  153. [self aspect_hookSelector:@selector(endRefreshing) withOptions:AspectPositionAfter usingBlock:block error:nil];
  154. [self aspect_hookSelector:@selector(endRefreshingCompletionBlock) withOptions:AspectPositionAfter usingBlock:block error:nil];
  155. }
  156. #pragma mark 是否正在刷新
  157. - (BOOL)isRefreshing
  158. {
  159. return self.state == MJRefreshStateRefreshing || self.state == MJRefreshStateWillRefresh;
  160. }
  161. #pragma mark 自动切换透明度
  162. - (void)setAutoChangeAlpha:(BOOL)autoChangeAlpha
  163. {
  164. self.automaticallyChangeAlpha = autoChangeAlpha;
  165. }
  166. - (BOOL)isAutoChangeAlpha
  167. {
  168. return self.isAutomaticallyChangeAlpha;
  169. }
  170. - (void)setAutomaticallyChangeAlpha:(BOOL)automaticallyChangeAlpha
  171. {
  172. _automaticallyChangeAlpha = automaticallyChangeAlpha;
  173. if (self.isRefreshing) return;
  174. if (automaticallyChangeAlpha) {
  175. self.alpha = self.pullingPercent;
  176. } else {
  177. self.alpha = 1.0;
  178. }
  179. }
  180. #pragma mark 根据拖拽进度设置透明度
  181. - (void)setPullingPercent:(CGFloat)pullingPercent
  182. {
  183. _pullingPercent = pullingPercent;
  184. if (self.isRefreshing) return;
  185. if (self.isAutomaticallyChangeAlpha) {
  186. self.alpha = pullingPercent;
  187. }
  188. }
  189. #pragma mark - 内部方法
  190. - (void)executeRefreshingCallback
  191. {
  192. MJRefreshDispatchAsyncOnMainQueue({
  193. if (self.refreshingBlock) {
  194. self.refreshingBlock();
  195. }
  196. if ([self.refreshingTarget respondsToSelector:self.refreshingAction]) {
  197. MJRefreshMsgSend(MJRefreshMsgTarget(self.refreshingTarget), self.refreshingAction, self);
  198. }
  199. if (self.beginRefreshingCompletionBlock) {
  200. self.beginRefreshingCompletionBlock();
  201. }
  202. })
  203. }
  204. @end
  205. @implementation UILabel(MJRefresh)
  206. + (instancetype)mj_label
  207. {
  208. UILabel *label = [[self alloc] init];
  209. label.font = MJRefreshLabelFont;
  210. label.textColor = MJRefreshLabelTextColor;
  211. label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  212. label.textAlignment = NSTextAlignmentCenter;
  213. label.backgroundColor = [UIColor clearColor];
  214. return label;
  215. }
  216. - (CGFloat)mj_textWith {
  217. CGFloat stringWidth = 0;
  218. CGSize size = CGSizeMake(MAXFLOAT, MAXFLOAT);
  219. if (self.text.length > 0) {
  220. #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
  221. stringWidth =[self.text
  222. boundingRectWithSize:size
  223. options:NSStringDrawingUsesLineFragmentOrigin
  224. attributes:@{NSFontAttributeName:self.font}
  225. context:nil].size.width;
  226. #else
  227. stringWidth = [self.text sizeWithFont:self.font
  228. constrainedToSize:size
  229. lineBreakMode:NSLineBreakByCharWrapping].width;
  230. #endif
  231. }
  232. return stringWidth;
  233. }
  234. @end