MJRefreshComponent.m 7.8 KB

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