JLRefreshHeader.m 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. //
  2. // JLRefreshHeader.m
  3. // JLRefreshDemo
  4. //
  5. // Created by Jack on 2017/3/6.
  6. // Copyright © 2017年 mini1. All rights reserved.
  7. //
  8. #import "JLRefreshHeader.h"
  9. @interface JLRefreshHeader ()
  10. @property (nonatomic,strong) NSMutableDictionary *stateTitle;
  11. @property (nonatomic,strong) UILabel *refreshTitleLabel;
  12. @end
  13. @implementation JLRefreshHeader
  14. #pragma mark - private
  15. - (NSMutableDictionary *)stateTitle {
  16. if (!_stateTitle) {
  17. _stateTitle = [@{
  18. @(JLRefreshStateIdle) : @"pull to refresh",
  19. @(JLRefreshStatePulling) : @"pull to refresh",
  20. @(JLRefreshStateWillRefresh) : @"loosen to refresh",
  21. @(JLRefreshStateRefreshing) : @"loading..."
  22. } mutableCopy];
  23. }
  24. return _stateTitle;
  25. }
  26. - (void)setRefreshTitleForState:(JLRefreshState)state {
  27. if (!self.clear) {
  28. self.refreshTitleLabel.text = [self refreshTitleForState:state];
  29. [self setNeedsLayout];
  30. }
  31. }
  32. #pragma mark - override
  33. - (void)layoutSubviews {
  34. [super layoutSubviews];
  35. self.jl_y = -self.jl_height;
  36. [self.refreshTitleLabel sizeToFit];
  37. CGRect frame = self.refreshTitleLabel.bounds;
  38. CGFloat Y = (CGRectGetHeight(self.bounds) - CGRectGetHeight(frame)) * 0.5;
  39. CGFloat X = (CGRectGetWidth(self.bounds) - CGRectGetWidth(frame)) * 0.5;
  40. self.refreshTitleLabel.jl_y = Y;
  41. self.refreshTitleLabel.jl_x = X;
  42. [self addSubview:self.refreshTitleLabel];
  43. }
  44. - (void)scrollViewContentOffsetDidChange:(NSDictionary<NSKeyValueChangeKey,id> *)change {
  45. if (self.offsetBlock) {
  46. self.offsetBlock(self.scrollView.jl_offsetY);
  47. }
  48. // 正在刷新
  49. if (self.state == JLRefreshStateRefreshing) {
  50. // 解决SectionHeader停留
  51. CGFloat insetTop = -self.scrollView.jl_offsetY > self.scrollViewOriginInsetTop ? -self.scrollView.jl_offsetY : self.scrollViewOriginInsetTop;
  52. insetTop = insetTop > self.jl_height + self.scrollViewOriginInsetTop ? self.jl_height + self.scrollViewOriginInsetTop : insetTop;
  53. self.scrollView.jl_insetTop = insetTop;
  54. return;
  55. }
  56. CGFloat offsetY = self.scrollView.jl_offsetY;
  57. CGFloat startY = -self.scrollView.jl_insetTop; // refresh 开始显示的临界点
  58. if (offsetY > startY) {
  59. return;
  60. }
  61. CGFloat idle2willRefreshY = startY - self.jl_height; // 正常状态到即将刷新状态临界点
  62. if (self.scrollView.isDragging) {
  63. if (self.state == JLRefreshStateIdle && offsetY < startY) {
  64. self.state = JLRefreshStatePulling;
  65. } else if (self.state == JLRefreshStatePulling && offsetY <= idle2willRefreshY) {
  66. self.state = JLRefreshStateWillRefresh;
  67. } else if (self.state == JLRefreshStatePulling && offsetY > startY) {
  68. self.state = JLRefreshStateIdle;
  69. } else if (self.state == JLRefreshStateWillRefresh && offsetY > idle2willRefreshY) {
  70. self.state = JLRefreshStatePulling;
  71. }
  72. float percentage = (startY - offsetY) / self.jl_height;
  73. if (percentage <= 0) {
  74. percentage = 0;
  75. }
  76. self.pullPercentage = percentage;
  77. if (self.refreshDelegate && [self.refreshDelegate respondsToSelector:@selector(jl_pullRefresh:state:percentage:)]) {
  78. [self.refreshDelegate jl_pullRefresh:self state:self.state percentage:self.pullPercentage];
  79. }
  80. }
  81. }
  82. - (void)scrollViewPanGestureStateDidChange:(NSDictionary<NSKeyValueChangeKey,id> *)change {
  83. if (self.pan.state == UIGestureRecognizerStateEnded && self.state == JLRefreshStateWillRefresh) {
  84. // 手松开开始刷新
  85. self.state = JLRefreshStateRefreshing;
  86. }
  87. }
  88. - (void)setState:(JLRefreshState)state {
  89. JLRefreshState oldState = self.state;
  90. if (state == oldState) {
  91. return;
  92. }
  93. if (self.stateChangeBlock) {
  94. self.stateChangeBlock(state);
  95. }
  96. super.state = state;
  97. dispatch_async(dispatch_get_main_queue(), ^{
  98. [self setRefreshTitleForState:state];
  99. });
  100. if (state == JLRefreshStateIdle) {
  101. // 恢复原状态
  102. if (oldState != JLRefreshStateRefreshing) {
  103. return;
  104. }
  105. __weak typeof(self) weakself = self;
  106. dispatch_async(dispatch_get_main_queue(), ^{
  107. [UIView animateWithDuration:JLRefreshDuration animations:^{
  108. weakself.scrollView.jl_insetTop = weakself.scrollViewOriginInsetTop;
  109. } completion:^(BOOL finished) {
  110. if (weakself.refreshDelegate && [weakself.refreshDelegate respondsToSelector:@selector(jl_endRefresh:)]) {
  111. dispatch_async(dispatch_get_main_queue(), ^{
  112. [weakself.refreshDelegate jl_endRefresh:weakself];
  113. });
  114. }
  115. }];
  116. });
  117. } else if (state == JLRefreshStatePulling) {
  118. // 下拉刷新
  119. } else if (state == JLRefreshStateWillRefresh) {
  120. // 松开刷新
  121. } else if (state == JLRefreshStateRefreshing) {
  122. // 正在刷新
  123. __weak typeof(self) weakself = self;
  124. dispatch_async(dispatch_get_main_queue(), ^{
  125. [UIView animateWithDuration:JLRefreshDuration animations:^{
  126. weakself.scrollView.jl_insetTop = weakself.jl_height;
  127. } completion:^(BOOL finished) {
  128. if (weakself.refreshDelegate && [weakself.refreshDelegate respondsToSelector:@selector(jl_beginRefresh:)]) {
  129. dispatch_async(dispatch_get_main_queue(), ^{
  130. [weakself.refreshDelegate jl_beginRefresh:weakself];
  131. });
  132. }
  133. }];
  134. });
  135. }
  136. }
  137. #pragma mark - Public
  138. - (void)setRefreshTitle:(NSString *)title forState:(JLRefreshState)state {
  139. if (title == nil) {
  140. return;
  141. }
  142. [self.stateTitle setObject:title forKey:@(state)];
  143. }
  144. - (NSString *)refreshTitleForState:(JLRefreshState)state {
  145. return [self.stateTitle objectForKey:@(state)];
  146. }
  147. #pragma mark - SubView
  148. - (UILabel *)refreshTitleLabel {
  149. if (!_refreshTitleLabel) {
  150. _refreshTitleLabel = [[UILabel alloc] init];
  151. _refreshTitleLabel.textAlignment = NSTextAlignmentCenter;
  152. _refreshTitleLabel.font = [UIFont systemFontOfSize:14.0f];
  153. }
  154. return _refreshTitleLabel;
  155. }
  156. @end