MJRefreshHeader.m 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. // MJRefreshHeader.m
  4. // MJRefreshExample
  5. //
  6. // Created by MJ Lee on 15/3/4.
  7. // Copyright (c) 2015年 小码哥. All rights reserved.
  8. //
  9. #import "MJRefreshHeader.h"
  10. @interface MJRefreshHeader()
  11. @property (assign, nonatomic) CGFloat insetTDelta;
  12. @end
  13. @implementation MJRefreshHeader
  14. #pragma mark - 构造方法
  15. + (instancetype)headerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock
  16. {
  17. MJRefreshHeader *cmp = [[self alloc] init];
  18. cmp.refreshingBlock = refreshingBlock;
  19. return cmp;
  20. }
  21. + (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action
  22. {
  23. MJRefreshHeader *cmp = [[self alloc] init];
  24. [cmp setRefreshingTarget:target refreshingAction:action];
  25. return cmp;
  26. }
  27. #pragma mark - 覆盖父类的方法
  28. - (void)prepare
  29. {
  30. [super prepare];
  31. // 设置key
  32. self.lastUpdatedTimeKey = MJRefreshHeaderLastUpdatedTimeKey;
  33. // 设置高度
  34. self.mj_h = MJRefreshHeaderHeight;
  35. }
  36. - (void)placeSubviews
  37. {
  38. [super placeSubviews];
  39. // 设置y值(当自己的高度发生改变了,肯定要重新调整Y值,所以放到placeSubviews方法中设置y值)
  40. self.mj_y = - self.mj_h - self.ignoredScrollViewContentInsetTop;
  41. }
  42. - (void)willMoveToWindow:(UIWindow *)newWindow {
  43. if (!newWindow && self.isRefreshing) {
  44. [self endRefreshing];
  45. }
  46. }
  47. - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
  48. {
  49. [super scrollViewContentOffsetDidChange:change];
  50. // 在刷新的refreshing状态
  51. if (self.state == MJRefreshStateRefreshing) {
  52. // 暂时保留
  53. if (self.window == nil) return;
  54. // sectionheader停留解决
  55. CGFloat insetT = - self.scrollView.mj_offsetY > _scrollViewOriginalInset.top ? - self.scrollView.mj_offsetY : _scrollViewOriginalInset.top;
  56. insetT = insetT > self.mj_h + _scrollViewOriginalInset.top ? self.mj_h + _scrollViewOriginalInset.top : insetT;
  57. self.scrollView.mj_insetT = insetT;
  58. self.insetTDelta = _scrollViewOriginalInset.top - insetT;
  59. return;
  60. }
  61. // 跳转到下一个控制器时,contentInset可能会变
  62. _scrollViewOriginalInset = self.scrollView.mj_inset;
  63. // 当前的contentOffset
  64. CGFloat offsetY = self.scrollView.mj_offsetY;
  65. // 头部控件刚好出现的offsetY
  66. CGFloat happenOffsetY = - self.scrollViewOriginalInset.top;
  67. // 如果是向上滚动到看不见头部控件,直接返回
  68. // >= -> >
  69. if (offsetY > happenOffsetY) return;
  70. // 普通 和 即将刷新 的临界点
  71. CGFloat normal2pullingOffsetY = happenOffsetY - self.mj_h;
  72. CGFloat pullingPercent = (happenOffsetY - offsetY) / self.mj_h;
  73. if (self.scrollView.isDragging) { // 如果正在拖拽
  74. self.pullingPercent = pullingPercent;
  75. if (self.state == MJRefreshStateIdle && offsetY < normal2pullingOffsetY) {
  76. // 转为即将刷新状态
  77. self.state = MJRefreshStatePulling;
  78. } else if (self.state == MJRefreshStatePulling && offsetY >= normal2pullingOffsetY) {
  79. // 转为普通状态
  80. self.state = MJRefreshStateIdle;
  81. }
  82. } else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开
  83. // 开始刷新
  84. [self beginRefreshing];
  85. } else if (pullingPercent < 1) {
  86. self.pullingPercent = pullingPercent;
  87. }
  88. }
  89. - (void)setState:(MJRefreshState)state
  90. {
  91. MJRefreshCheckState
  92. // 根据状态做事情
  93. if (state == MJRefreshStateIdle) {
  94. if (oldState != MJRefreshStateRefreshing) return;
  95. // 保存刷新时间
  96. [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:self.lastUpdatedTimeKey];
  97. [[NSUserDefaults standardUserDefaults] synchronize];
  98. // 恢复inset和offset
  99. [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
  100. self.scrollView.mj_insetT += self.insetTDelta;
  101. // 自动调整透明度
  102. if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0;
  103. } completion:^(BOOL finished) {
  104. self.pullingPercent = 0.0;
  105. if (self.endRefreshingCompletionBlock) {
  106. self.endRefreshingCompletionBlock();
  107. }
  108. }];
  109. } else if (state == MJRefreshStateRefreshing) {
  110. MJRefreshDispatchAsyncOnMainQueue({
  111. [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
  112. if (self.scrollView.panGestureRecognizer.state != UIGestureRecognizerStateCancelled) {
  113. CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
  114. // 增加滚动区域top
  115. self.scrollView.mj_insetT = top;
  116. // 设置滚动位置
  117. CGPoint offset = self.scrollView.contentOffset;
  118. offset.y = -top;
  119. [self.scrollView setContentOffset:offset animated:NO];
  120. }
  121. } completion:^(BOOL finished) {
  122. [self executeRefreshingCallback];
  123. }];
  124. })
  125. }
  126. }
  127. #pragma mark - 公共方法
  128. - (NSDate *)lastUpdatedTime
  129. {
  130. return [[NSUserDefaults standardUserDefaults] objectForKey:self.lastUpdatedTimeKey];
  131. }
  132. - (void)setIgnoredScrollViewContentInsetTop:(CGFloat)ignoredScrollViewContentInsetTop {
  133. _ignoredScrollViewContentInsetTop = ignoredScrollViewContentInsetTop;
  134. self.mj_y = - self.mj_h - _ignoredScrollViewContentInsetTop;
  135. }
  136. @end