| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- //
- // JLRefreshFooter.m
- // JLRefreshDemo
- //
- // Created by Jack on 2017/3/7.
- // Copyright © 2017年 mini1. All rights reserved.
- //
- #import "JLRefreshFooter.h"
- CGFloat const JLRefreshFooterHeight = 30;
- @interface JLRefreshFooter ()
- @property (nonatomic,strong) NSMutableDictionary *stateTitle;
- @property (nonatomic,strong) UILabel *refreshTitleLabel;
- @property (nonatomic,assign) BOOL stopWithNomore;
- @property (nonatomic,assign) BOOL autoRefresh;
- @end
- @implementation JLRefreshFooter
- - (void)prepareInterface {
- [super prepareInterface];
-
- self.jl_height = JLRefreshFooterHeight;
- }
- #pragma mark - SubView
- - (UILabel *)refreshTitleLabel {
- if (!_refreshTitleLabel) {
- _refreshTitleLabel = [[UILabel alloc] init];
- _refreshTitleLabel.textAlignment = NSTextAlignmentCenter;
- _refreshTitleLabel.font = [UIFont systemFontOfSize:14.0f];
- // _refreshTitleLabel.hidden = YES;
- }
- return _refreshTitleLabel;
- }
- #pragma mark - Private
- - (BOOL)contentSizeIsOutOfScrollViewBounds {
- // top + content > height
- return self.scrollView.jl_insetTop + self.scrollView.jl_ContentHeight > self.scrollView.jl_height;
- }
- - (NSMutableDictionary *)stateTitle {
- if (!_stateTitle) {
- _stateTitle = [@{
- @(JLRefreshStateIdle) : @"pull to load more",
- @(JLRefreshStatePulling) : @"will load more",
- @(JLRefreshStateWillRefresh) : @"loosen to load more",
- @(JLRefreshStateRefreshing) : @"loading...",
- @(JLRefreshStateNoMore) : @"no more"
- } mutableCopy];
- }
- return _stateTitle;
- }
- - (void)setRefreshTitleForState:(JLRefreshState)state {
- if (!self.clear) {
- self.refreshTitleLabel.text = [self refreshTitleForState:state];
- [self setNeedsLayout];
- }
- }
- #pragma mark - Override
- - (void)layoutSubviews {
- [super layoutSubviews];
-
-
- [self.refreshTitleLabel sizeToFit];
- CGRect frame = self.refreshTitleLabel.bounds;
- CGFloat Y = (CGRectGetHeight(self.bounds) - CGRectGetHeight(frame)) * 0.5;
- CGFloat X = (CGRectGetWidth(self.bounds) - CGRectGetWidth(frame)) * 0.5;
- self.refreshTitleLabel.jl_y = Y;
- self.refreshTitleLabel.jl_x = X;
-
- [self addSubview:self.refreshTitleLabel];
-
- }
- - (void)willMoveToSuperview:(UIView *)newSuperview {
-
- [super willMoveToSuperview:newSuperview];
-
- if (newSuperview) { // add
-
- self.scrollView.jl_insetBottom += self.jl_height;
-
- // self.jl_y = self.scrollView.jl_ContentHeight;
- // 设置位置
- self.jl_y = (((int)(self.scrollView.jl_ContentHeight / self.scrollView.jl_height)) + 1) * self.scrollView.jl_height;
-
- } else { // remove
-
- self.scrollView.jl_insetBottom -= self.jl_height;
-
- }
-
- }
- - (void)scrollViewContentSizeDidChange:(NSDictionary<NSKeyValueChangeKey,id> *)change {
-
- [super scrollViewContentSizeDidChange:change];
-
- // self.jl_y = self.scrollView.jl_ContentHeight;
- // 设置位置
- // if (self.scrollView.jl_ContentHeight >= self.scrollView.jl_height) {
- // self.jl_y = self.scrollView.jl_ContentHeight;
- // } else {
- // self.jl_y = self.scrollView.jl_height;
- // }
-
- self.jl_y = (((int)(self.scrollView.jl_ContentHeight / self.scrollView.jl_height)) + 1) * self.scrollView.jl_height;
-
- if (self.offsetBlock) {
- self.offsetBlock(0);
- }
- }
- - (void)scrollViewContentOffsetDidChange:(NSDictionary<NSKeyValueChangeKey,id> *)change {
-
- [super scrollViewContentOffsetDidChange:change];
- if (self.offsetBlock) {
- self.offsetBlock(self.scrollView.jl_ContentHeight - self.scrollView.jl_offsetY - self.scrollView.jl_height);
- }
-
- if (self.state == JLRefreshStateRefreshing) {
- return;
- }
-
- CGFloat offsetY = self.scrollView.jl_offsetY + self.scrollView.jl_height;
- CGFloat startY = self.scrollView.jl_insetBottom + self.scrollView.jl_ContentHeight - self.jl_height;
- CGFloat idle2WillRefresh = startY + self.jl_height * 1.5;
-
- if ([self contentSizeIsOutOfScrollViewBounds]) {
-
-
- if (offsetY < startY) {
- return;
- }
-
- // autoRefresh 修复拖拽松手后,减速完成触底时状态WillRefresh改变Idle,界面闪一下。
- if (self.scrollView.isDragging && self.autoRefresh) {
-
- // NSLog(@"%d -> %d",0,self.state);
-
- if (self.state == JLRefreshStateNoMore) {
-
- self.state = JLRefreshStateIdle;
-
- } else if (self.state == JLRefreshStateIdle) { // 1
-
- self.state = JLRefreshStatePulling; // 2
-
- } else if (self.state == JLRefreshStatePulling && offsetY < startY) {
-
- self.state = JLRefreshStateIdle;
-
- } else if (self.state == JLRefreshStatePulling && offsetY >= idle2WillRefresh) { // 完全显示出来才刷新
-
- self.state = JLRefreshStateWillRefresh; // 4
-
- }
-
-
-
- } else {
- // NSLog(@"%d -> %d",1,self.state);
- if (self.state != JLRefreshStateRefreshing) {
- if (self.stopWithNomore) {
- [self setState:JLRefreshStateNoMore];
- }
- if (self.state != JLRefreshStateNoMore) {
- self.state = JLRefreshStateIdle;
- }
- }
- }
-
- float percentage = (offsetY - startY) / self.jl_height;
- if (percentage < 0) {
- percentage = 0;
- }
- self.pullPercentage = percentage;
-
- [self showTip];
- if (self.refreshDelegate && [self.refreshDelegate respondsToSelector:@selector(jl_pullRefresh:state:percentage:)]) {
- [self.refreshDelegate jl_pullRefresh:self state:self.state percentage:self.pullPercentage];
- }
-
-
- } else {
-
- CGPoint old = [change[@"old"] CGPointValue];
- CGPoint new = [change[@"new"] CGPointValue];
- // NSLog(@"%d -> %d",2,self.state);
-
- if (self.scrollView.jl_insetTop == self.scrollViewOriginInsetTop && new.y > -self.scrollViewOriginInsetTop && old.y < new.y) { // 上拉,在未超出height的范围内拖动都视为刷新
-
- if (self.state == JLRefreshStateRefreshing) return;
-
- if (self.scrollView.isDragging) {
- self.state = JLRefreshStateWillRefresh;
- self.pullPercentage = 1;
- [self showTip];
- if (self.refreshDelegate && [self.refreshDelegate respondsToSelector:@selector(jl_pullRefresh:state:percentage:)]) {
- [self.refreshDelegate jl_pullRefresh:self state:self.state percentage:self.pullPercentage];
- }
- }
-
- }
-
- }
-
-
-
-
- }
- - (void)scrollViewPanGestureStateDidChange:(NSDictionary<NSKeyValueChangeKey,id> *)change {
-
- [super scrollViewPanGestureStateDidChange:change];
- // NSLog(@"%d -> %d",3,self.state);
-
- if (self.pan.state == UIGestureRecognizerStateBegan) {
- self.autoRefresh = YES;
- }
- if (self.pan.state == UIGestureRecognizerStateEnded) {
-
- if (self.state == JLRefreshStateWillRefresh) {
- self.state = JLRefreshStateRefreshing;
- } else {
- self.autoRefresh = NO;
- }
- }
-
- }
- #pragma mark - Setter
- - (void)setState:(JLRefreshState)state {
-
- JLRefreshState oldState = self.state;
-
- if (self.stateChangeBlock) {
- self.stateChangeBlock(state);
- }
-
- if (state == oldState) {
- return;
- }
- super.state = state;
-
- __weak typeof(self) weakself = self;
- dispatch_async(dispatch_get_main_queue(), ^{
- [weakself setRefreshTitleForState:state];
- });
-
-
- if (state == JLRefreshStateIdle || state == JLRefreshStateNoMore) {
-
- if (oldState != JLRefreshStateRefreshing) {
- return;
- }
-
- if (weakself.refreshDelegate && [weakself.refreshDelegate respondsToSelector:@selector(jl_endRefresh:)]) {
-
- dispatch_async(dispatch_get_main_queue(), ^{
- [weakself.refreshDelegate jl_endRefresh:weakself];
- });
-
- }
-
- } else if (state == JLRefreshStatePulling) {
-
-
- } else if (state == JLRefreshStateWillRefresh) {
-
-
- } else if (state == JLRefreshStateRefreshing) {
-
- if (weakself.refreshDelegate && [weakself.refreshDelegate respondsToSelector:@selector(jl_beginRefresh:)]) {
-
- dispatch_async(dispatch_get_main_queue(), ^{
- weakself.stopWithNomore = NO;
- [weakself.refreshDelegate jl_beginRefresh:weakself];
- });
-
- }
-
- }
-
- }
- #pragma mark - Public
- - (void)noMoreData {
- self.state = JLRefreshStateNoMore;
- if (self.scrollView.isDecelerating) {
- self.stopWithNomore = YES; // Scrollviewc重新刷新数据后才能赋值NO
- }
- }
- - (void)showTip {
- self.refreshTitleLabel.hidden = NO;
- }
- - (void)setRefreshTitle:(NSString *)title forState:(JLRefreshState)state {
- if (title == nil) {
- return;
- }
-
- [self.stateTitle setObject:title forKey:@(state)];
- }
- - (NSString *)refreshTitleForState:(JLRefreshState)state {
- return [self.stateTitle objectForKey:@(state)];
- }
- @end
|