UITableView 下拉刷新的实现

UITableView下拉刷新的实现原理是自定义的下拉刷新控件KVO监听UITableView(UIScrollView)的 contentOffset 属性。

#import 

typedef void (^RefreshHeaderBlock)(void);

@interface RefreshHeader : UIView

- (instancetype)initWithTarget:(id)target beginRefreshBlock:(RefreshHeaderBlock)refreshHeaderBlock;

- (void)beginRefreshing;

- (void)endRefreshing;

@end

把UITableView(UIScrollView)传进来作为目标,添加监听

@implementation RefreshHeader
- (instancetype)initWithTarget:(id)target beginRefreshBlock:(RefreshHeaderBlock)refreshHeaderBlock{
    self = [super init];
    if (self) {
        self.frame = CGRectMake(0, 0, 0, HeaderHeight);
        _refreshHeaderBlock = refreshHeaderBlock;

        _scrollView = (UIScrollView *)target;
        [_scrollView addSubview:self];
        NSKeyValueObservingOptions option = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
        [_scrollView addObserver:self forKeyPath:RefreshHeaderKeyPathContentOffset options:option context:nil];
    }
    return self;
}
- (void)layoutSubviews{
    [super layoutSubviews];
    CGFloat superWidth = self.scrollView.frame.size.width;
    self.frame = CGRectMake(0, - HeaderHeight, superWidth, HeaderHeight);
    ......
}

#pragma mark public
- (void)beginRefreshing{
    if (!_isRefresh) {
        
        _isRefresh = YES;
        
        //设置偏移量,衔接加载的更多数据
        [UIView animateWithDuration:0.3 animations:^{
            //刷新控件停留
            [_scrollView setContentInset:UIEdgeInsetsMake(HeaderHeight, 0, 0, 0)];
            
            [self.activityView startAnimating];
            self.arrowView.hidden = YES;
            self.stateLable.text = @"加载中";
        }];
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            _refreshHeaderBlock();
        });
    }
}

- (void)endRefreshing{
    _isRefresh = NO;
    
    [UIView animateWithDuration:0.3 animations:^{
        [self.activityView stopAnimating];
        self.arrowView.hidden = YES;
        self.arrowView.transform =  CGAffineTransformMakeRotation(M_PI*2);
        
        //还原scrollView
        [self.scrollView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
    }];
}

#pragma mark KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if ([keyPath isEqualToString:RefreshHeaderKeyPathContentOffset]) {
        [self scrollViewContentOffsetDidChange:change];
    }else{
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

#pragma mark logicol
//判断contentOffset<0代表手势为往下拖动,根据isDragging属性判断是否松开,如果松开且偏移量大于(HeaderHeight),启动刷新动作
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change{
    
    self.stateLable.hidden = NO;
    CGFloat offset = self.scrollView.contentOffset.y;
    if (offset < 0) {
        //正在拖拽
        if(self.scrollView.isDragging){
            //还原scrollView
            [self.scrollView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
            
            [UIView animateWithDuration:0.3 animations:^{
                self.arrowView.hidden = NO;
                if (offset < -HeaderHeight*1.5) {
                    self.arrowView.transform =  CGAffineTransformMakeRotation(M_PI);
                    self.stateLable.text = @"释放更新";
                }else{
                    self.arrowView.transform =  CGAffineTransformMakeRotation(M_PI*2);
                    self.stateLable.text = @"载入更多";
                }
            }];
            
            return;
        }
        
        //松开且偏移量大于头部高度,启动刷新
        if (offset < -HeaderHeight) {
            [self beginRefreshing];
        }
    }
}

-(void)dealloc{
    [self.scrollView removeObserver:self forKeyPath:RefreshHeaderKeyPathContentOffset];
}

demo

你可能感兴趣的:(UITableView 下拉刷新的实现)