// // 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; @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) : @"pull to 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 *)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 *)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; } if (self.scrollView.isDragging) { 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 { // 停止拖动的减速过程 if (self.state != JLRefreshStateRefreshing && offsetY >= idle2WillRefresh) { self.state = JLRefreshStateRefreshing; } else { 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]; 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 *)change { [super scrollViewPanGestureStateDidChange:change]; if (self.pan.state == UIGestureRecognizerStateEnded) { if (self.state == JLRefreshStateWillRefresh) { self.state = JLRefreshStateRefreshing; } } } #pragma mark - Setter - (void)setState:(JLRefreshState)state { JLRefreshState oldState = self.state; if (state == oldState) { return; } if (self.stateChangeBlock) { self.stateChangeBlock(state); } 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