MJRefreshBackFooter.m 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. //
  2. // MJRefreshBackFooter.m
  3. // MJRefresh
  4. //
  5. // Created by MJ Lee on 15/4/24.
  6. // Copyright (c) 2015年 小码哥. All rights reserved.
  7. //
  8. #import "MJRefreshBackFooter.h"
  9. #import "NSBundle+MJRefresh.h"
  10. #import "UIView+MJExtension.h"
  11. #import "UIScrollView+MJExtension.h"
  12. #import "UIScrollView+MJRefresh.h"
  13. @interface MJRefreshBackFooter()
  14. @property (assign, nonatomic) NSInteger lastRefreshCount;
  15. @property (assign, nonatomic) CGFloat lastBottomDelta;
  16. @end
  17. @implementation MJRefreshBackFooter
  18. #pragma mark - 初始化
  19. - (void)willMoveToSuperview:(UIView *)newSuperview
  20. {
  21. [super willMoveToSuperview:newSuperview];
  22. [self scrollViewContentSizeDidChange:nil];
  23. }
  24. #pragma mark - 实现父类的方法
  25. - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
  26. {
  27. [super scrollViewContentOffsetDidChange:change];
  28. // 如果正在刷新,直接返回
  29. if (self.state == MJRefreshStateRefreshing) return;
  30. _scrollViewOriginalInset = self.scrollView.mj_inset;
  31. // 当前的contentOffset
  32. CGFloat currentOffsetY = self.scrollView.mj_offsetY;
  33. // 尾部控件刚好出现的offsetY
  34. CGFloat happenOffsetY = [self happenOffsetY];
  35. // 如果是向下滚动到看不见尾部控件,直接返回
  36. if (currentOffsetY <= happenOffsetY) return;
  37. CGFloat pullingPercent = (currentOffsetY - happenOffsetY) / self.mj_h;
  38. // 如果已全部加载,仅设置pullingPercent,然后返回
  39. if (self.state == MJRefreshStateNoMoreData) {
  40. self.pullingPercent = pullingPercent;
  41. return;
  42. }
  43. if (self.scrollView.isDragging) {
  44. self.pullingPercent = pullingPercent;
  45. // 普通 和 即将刷新 的临界点
  46. CGFloat normal2pullingOffsetY = happenOffsetY + self.mj_h;
  47. if (self.state == MJRefreshStateIdle && currentOffsetY > normal2pullingOffsetY) {
  48. // 转为即将刷新状态
  49. self.state = MJRefreshStatePulling;
  50. } else if (self.state == MJRefreshStatePulling && currentOffsetY <= normal2pullingOffsetY) {
  51. // 转为普通状态
  52. self.state = MJRefreshStateIdle;
  53. }
  54. } else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开
  55. // 开始刷新
  56. [self beginRefreshing];
  57. } else if (pullingPercent < 1) {
  58. self.pullingPercent = pullingPercent;
  59. }
  60. }
  61. - (void)scrollViewContentSizeDidChange:(NSDictionary *)change
  62. {
  63. [super scrollViewContentSizeDidChange:change];
  64. CGSize size = [change[NSKeyValueChangeNewKey] CGSizeValue];
  65. CGFloat contentHeight = size.height == 0 ? self.scrollView.mj_contentH : size.height;
  66. // 内容的高度
  67. contentHeight += self.ignoredScrollViewContentInsetBottom;
  68. // 表格的高度
  69. CGFloat scrollHeight = self.scrollView.mj_h - self.scrollViewOriginalInset.top - self.scrollViewOriginalInset.bottom + self.ignoredScrollViewContentInsetBottom;
  70. // 设置位置
  71. CGFloat y = MAX(contentHeight, scrollHeight);
  72. if (self.mj_y != y) {
  73. self.mj_y = y;
  74. }
  75. }
  76. - (void)setState:(MJRefreshState)state
  77. {
  78. MJRefreshCheckState
  79. // 根据状态来设置属性
  80. if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
  81. // 刷新完毕
  82. if (MJRefreshStateRefreshing == oldState) {
  83. [UIView animateWithDuration:self.slowAnimationDuration animations:^{
  84. if (self.endRefreshingAnimationBeginAction) {
  85. self.endRefreshingAnimationBeginAction();
  86. }
  87. self.scrollView.mj_insetB -= self.lastBottomDelta;
  88. // 自动调整透明度
  89. if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0;
  90. } completion:^(BOOL finished) {
  91. self.pullingPercent = 0.0;
  92. if (self.endRefreshingCompletionBlock) {
  93. self.endRefreshingCompletionBlock();
  94. }
  95. }];
  96. }
  97. CGFloat deltaH = [self heightForContentBreakView];
  98. // 刚刷新完毕
  99. if (MJRefreshStateRefreshing == oldState && deltaH > 0 && self.scrollView.mj_totalDataCount != self.lastRefreshCount) {
  100. self.scrollView.mj_offsetY = self.scrollView.mj_offsetY;
  101. }
  102. } else if (state == MJRefreshStateRefreshing) {
  103. // 记录刷新前的数量
  104. self.lastRefreshCount = self.scrollView.mj_totalDataCount;
  105. [UIView animateWithDuration:self.fastAnimationDuration animations:^{
  106. CGFloat bottom = self.mj_h + self.scrollViewOriginalInset.bottom;
  107. CGFloat deltaH = [self heightForContentBreakView];
  108. if (deltaH < 0) { // 如果内容高度小于view的高度
  109. bottom -= deltaH;
  110. }
  111. self.lastBottomDelta = bottom - self.scrollView.mj_insetB;
  112. self.scrollView.mj_insetB = bottom;
  113. self.scrollView.mj_offsetY = [self happenOffsetY] + self.mj_h;
  114. } completion:^(BOOL finished) {
  115. [self executeRefreshingCallback];
  116. }];
  117. }
  118. }
  119. #pragma mark - 私有方法
  120. #pragma mark 获得scrollView的内容 超出 view 的高度
  121. - (CGFloat)heightForContentBreakView
  122. {
  123. CGFloat h = self.scrollView.frame.size.height - self.scrollViewOriginalInset.bottom - self.scrollViewOriginalInset.top;
  124. return self.scrollView.contentSize.height - h;
  125. }
  126. #pragma mark 刚好看到上拉刷新控件时的contentOffset.y
  127. - (CGFloat)happenOffsetY
  128. {
  129. CGFloat deltaH = [self heightForContentBreakView];
  130. if (deltaH > 0) {
  131. return deltaH - self.scrollViewOriginalInset.top;
  132. } else {
  133. return - self.scrollViewOriginalInset.top;
  134. }
  135. }
  136. @end