No Description

FKRefreshControl.m 10.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. //
  2. // FKRefreshControl.m
  3. // FirstLink
  4. //
  5. // Created by jack on 15/12/1.
  6. // Copyright © 2015年 FirstLink. All rights reserved.
  7. //
  8. #import "FKRefreshControl.h"
  9. #import "RefreshTopView.h"
  10. #import "RefreshBottomView.h"
  11. #import "RefreshViewDelegate.h"
  12. @interface FKRefreshControl ()
  13. @property (nonatomic,weak)id<FKRefreshControlDelegate>delegate;
  14. @property (nonatomic,strong)UIView * topView;
  15. @property (nonatomic,strong)UIView * bottomView;
  16. @property (nonatomic,copy)NSString * topClass;
  17. @property (nonatomic,copy)NSString * bottomClass;
  18. @end
  19. @implementation FKRefreshControl
  20. - (void)registerClassForTopView:(Class)topClass
  21. {
  22. if ([topClass conformsToProtocol:@protocol(RefreshViewDelegate)]) {
  23. self.topClass=NSStringFromClass([topClass class]);
  24. }
  25. else{
  26. self.topClass=NSStringFromClass([RefreshTopView class]);
  27. }
  28. }
  29. - (void)registerClassForBottomView:(Class)bottomClass
  30. {
  31. if ([bottomClass conformsToProtocol:@protocol(RefreshViewDelegate)]) {
  32. self.bottomClass=NSStringFromClass([bottomClass class]);
  33. }
  34. else{
  35. self.bottomClass=NSStringFromClass([RefreshBottomView class]);
  36. }
  37. }
  38. - (instancetype)initWithScrollView:(UIScrollView *)scrollView delegate:(id<FKRefreshControlDelegate>)delegate
  39. {
  40. self=[super init];
  41. if (self)
  42. {
  43. _scrollView=scrollView;
  44. _delegate=delegate;
  45. _topClass=NSStringFromClass([RefreshTopView class]);
  46. _bottomClass=NSStringFromClass([RefreshBottomView class]);
  47. self.enableInsetTop=65.0;
  48. self.enableInsetBottom=65.0;
  49. [_scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];
  50. [_scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld|NSKeyValueObservingOptionPrior context:NULL];
  51. }
  52. return self;
  53. }
  54. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
  55. {
  56. if([keyPath isEqual:@"contentSize"])
  57. {
  58. if (self.topEnabled)
  59. {
  60. [self initTopView];
  61. }
  62. if (self.bottomEnabled)
  63. {
  64. [self initBottonView];
  65. }
  66. }
  67. else if([keyPath isEqualToString:@"contentOffset"])
  68. {
  69. if (_refreshingDirection==RefreshingDirectionNone) {
  70. [self _drogForChange:change];
  71. }
  72. }
  73. }
  74. - (void)_drogForChange:(NSDictionary *)change
  75. {
  76. if ( self.topEnabled && self.scrollView.contentOffset.y<0)
  77. {
  78. if(self.scrollView.contentOffset.y<-self.enableInsetTop)
  79. {
  80. if (self.autoRefreshTop || ( self.scrollView.decelerating && self.scrollView.dragging==NO)) {
  81. [self _engageRefreshDirection:RefreshDirectionTop];
  82. }
  83. else {
  84. [self _canEngageRefreshDirection:RefreshDirectionTop];
  85. }
  86. }
  87. else
  88. {
  89. [self _didDisengageRefreshDirection:RefreshDirectionTop];
  90. }
  91. }
  92. if ( self.bottomEnabled && self.scrollView.contentOffset.y>0 )
  93. {
  94. if(self.scrollView.contentOffset.y>(self.scrollView.contentSize.height+self.enableInsetBottom-self.scrollView.bounds.size.height) )
  95. {
  96. if(self.autoRefreshBottom || (self.scrollView.decelerating && self.scrollView.dragging==NO)){
  97. [self _engageRefreshDirection:RefreshDirectionBottom];
  98. }
  99. else{
  100. [self _canEngageRefreshDirection:RefreshDirectionBottom];
  101. }
  102. }
  103. else {
  104. [self _didDisengageRefreshDirection:RefreshDirectionBottom];
  105. }
  106. }
  107. }
  108. - (void)_canEngageRefreshDirection:(RefreshDirection) direction
  109. {
  110. if (direction==RefreshDirectionTop)
  111. {
  112. [self.topView performSelector:@selector(canEngageRefresh)];
  113. //[self.topView canEngageRefresh];
  114. }
  115. else if (direction==RefreshDirectionBottom)
  116. {
  117. [self.bottomView performSelector:@selector(canEngageRefresh)];
  118. //[self.bottomView canEngageRefresh];
  119. }
  120. }
  121. - (void)_didDisengageRefreshDirection:(RefreshDirection) direction
  122. {
  123. if (direction==RefreshDirectionTop)
  124. {
  125. [self.topView performSelector:@selector(didDisengageRefresh)];
  126. //[self.topView didDisengageRefresh];
  127. }
  128. else if (direction==RefreshDirectionBottom)
  129. {
  130. [self.bottomView performSelector:@selector(didDisengageRefresh)];
  131. //[self.bottomView didDisengageRefresh];
  132. }
  133. }
  134. - (void)_engageRefreshDirection:(RefreshDirection) direction
  135. {
  136. UIEdgeInsets edge = UIEdgeInsetsZero;
  137. if (direction==RefreshDirectionTop)
  138. {
  139. _refreshingDirection=RefreshingDirectionTop;
  140. float topH=self.enableInsetTop<45?45:self.enableInsetTop;
  141. edge=UIEdgeInsetsMake(topH, 0, 0, 0);///enableInsetTop
  142. }
  143. else if (direction==RefreshDirectionBottom)
  144. {
  145. float botomH=self.enableInsetBottom<50?50:self.enableInsetBottom;
  146. edge=UIEdgeInsetsMake(0, 0, botomH, 0);///self.enableInsetBottom
  147. _refreshingDirection=RefreshingDirectionBottom;
  148. }
  149. _scrollView.contentInset=edge;
  150. [self _didEngageRefreshDirection:direction];
  151. }
  152. - (void)_didEngageRefreshDirection:(RefreshDirection) direction
  153. {
  154. if (direction==RefreshDirectionTop)
  155. {
  156. [self.topView performSelector:@selector(startRefreshing)];
  157. //[self.topView startRefreshing];
  158. }
  159. else if (direction==RefreshDirectionBottom)
  160. {
  161. [self.bottomView performSelector:@selector(startRefreshing)];
  162. // [self.bottomView startRefreshing];
  163. }
  164. if ([self.delegate respondsToSelector:@selector(refreshControl:didEngageRefreshDirection:)])
  165. {
  166. [self.delegate refreshControl:self didEngageRefreshDirection:direction];
  167. }
  168. }
  169. - (void)_startRefreshingDirection:(RefreshDirection)direction animation:(BOOL)animation
  170. {
  171. CGPoint point =CGPointZero;
  172. if (direction==RefreshDirectionTop)
  173. {
  174. float topH=self.enableInsetTop<45?45:self.enableInsetTop;
  175. point=CGPointMake(0, -topH);//enableInsetTop
  176. }
  177. else if (direction==RefreshDirectionBottom)
  178. {
  179. float height=MAX(self.scrollView.contentSize.height, self.scrollView.frame.size.height);
  180. float bottomH=self.enableInsetBottom<45?45:self.enableInsetBottom;
  181. point=CGPointMake(0, height-self.scrollView.bounds.size.height+bottomH);///enableInsetBottom
  182. }
  183. __weak typeof(self)weakSelf=self;
  184. [_scrollView setContentOffset:point animated:YES];
  185. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  186. __strong typeof(self)strongSelf=weakSelf;
  187. [strongSelf _engageRefreshDirection:direction];
  188. });
  189. }
  190. - (void)_finishRefreshingDirection1:(RefreshDirection)direction animation:(BOOL)animation
  191. {
  192. [UIView animateWithDuration:0.25 animations:^{
  193. _scrollView.contentInset=UIEdgeInsetsZero;
  194. } completion:^(BOOL finished) {
  195. }];
  196. _refreshingDirection=RefreshingDirectionNone;
  197. if (direction==RefreshDirectionTop)
  198. {
  199. [self.topView performSelector:@selector(finishRefreshing)];
  200. //[self.topView finishRefreshing];
  201. }
  202. else if(direction==RefreshDirectionBottom)
  203. {
  204. [self.bottomView performSelector:@selector(finishRefreshing)];
  205. //[self.bottomView finishRefreshing];
  206. }
  207. }
  208. - (void)dealloc
  209. {
  210. [_scrollView removeObserver:self forKeyPath:@"contentSize"];
  211. [_scrollView removeObserver:self forKeyPath:@"contentOffset"];
  212. }
  213. - (void)initTopView
  214. {
  215. if (!CGRectIsEmpty(self.scrollView.frame))
  216. {
  217. float topOffsetY=self.enableInsetTop+45*6;
  218. if (self.topView==nil)
  219. {
  220. Class className=NSClassFromString(self.topClass);
  221. _topView=[[className alloc] initWithFrame:CGRectMake(0, -topOffsetY, self.scrollView.frame.size.width, topOffsetY)];
  222. [self.scrollView addSubview:self.topView];
  223. }
  224. else{
  225. _topView.frame=CGRectMake(0, -topOffsetY, self.scrollView.frame.size.width, topOffsetY);
  226. [_topView performSelector:@selector(resetLayoutSubViews)];
  227. //[_topView resetLayoutSubViews];
  228. }
  229. }
  230. }
  231. - (void)initBottonView
  232. {
  233. if (!CGRectIsNull(self.scrollView.frame))
  234. {
  235. float y=MAX(self.scrollView.bounds.size.height, self.scrollView.contentSize.height);
  236. if (self.bottomView==nil)
  237. {
  238. Class className=NSClassFromString(self.bottomClass);
  239. _bottomView=[[className alloc] initWithFrame:CGRectMake(0,y , self.scrollView.bounds.size.width, self.enableInsetBottom+45)];
  240. [self.scrollView addSubview:_bottomView];
  241. }
  242. else{
  243. _bottomView.frame=CGRectMake(0,y , self.scrollView.bounds.size.width, self.enableInsetBottom+45*6);
  244. [self.bottomView performSelector:@selector(resetLayoutSubViews)];
  245. //[self.bottomView resetLayoutSubViews];
  246. }
  247. }
  248. }
  249. - (void)setTopEnabled:(BOOL)topEnabled
  250. {
  251. _topEnabled=topEnabled;
  252. if (_topEnabled)
  253. {
  254. if (self.topView==nil)
  255. {
  256. [self initTopView];
  257. }
  258. }
  259. else{
  260. [self.topView removeFromSuperview];
  261. self.topView=nil;
  262. }
  263. }
  264. - (void)setBottomEnabled:(BOOL)bottomEnabled
  265. {
  266. _bottomEnabled=bottomEnabled;
  267. if (_bottomEnabled)
  268. {
  269. if (_bottomView==nil)
  270. {
  271. [self initBottonView];
  272. }
  273. }
  274. else{
  275. [_bottomView removeFromSuperview];
  276. _bottomView=nil;
  277. }
  278. }
  279. - (void)startRefreshingDirection:(RefreshDirection)direction
  280. {
  281. [self _startRefreshingDirection:direction animation:YES];
  282. }
  283. - (void)finishRefreshingDirection:(RefreshDirection)direction
  284. {
  285. [self _finishRefreshingDirection1:direction animation:YES];
  286. }
  287. @end