iOS自定义下拉刷新控件--保持刷新动画位置不变

说到下拉刷新我想都会想到MJRefresh,虽然它很强大,但是有些需求还是办不到,只能自定义.如下图:



下拉2.gif

MJRefresh是将动画图片放在scrollview的顶部,使动画图片与scrollview在同一级,并且随着scrollview的滑动而滑动.而上图中的效果是将动画放在视图控制器上,并且在tableview上面,而且根据tableview滑动改变透明度.
我的思路大概是这样的:

1.这个自定义的View能随着scrollview滑动而改变自身的状态,并且它的X需要在scrollview的中间,Y在scrollview下面一点那么说明View需要持有scrollview,.

2.在View里面监听ScrollView的contentOffset属性,来做相应的处理.

3.刷新状态大致分为闲置状态,正在刷新和结束刷新3种.

4.正在刷新的时候需要改变scrollView的contentInset,并在刷新结束后恢复.

好了,沿着这个思路开干吧,代码量非常少,只有一个文件.

MHRefreshHeader.h

#import 
UIKIT_EXTERN NSString *const BaseRefreshViewObserveKeyPath;
typedef enum {
    MHRefreshStateNormal,//闲置状态
    MHRefreshStateRefreshing,//正在刷新
    MHRefreshStateEndRresh,//结束刷新
} MHRefreshViewState;
@interface MHRefreshHeader : UIView
@property (nonatomic, copy) void(^refreshingBlock)(void);
@property(nonatomic,strong) UIImageView *refreshImageView;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, assign) MHRefreshViewState refreshState;

- (void)endRefreshing;
+(instancetype)refreshWithScroll:(UIScrollView *)scrollView;
@end

MHRefreshHeader.m

#import "MHRefreshHeader.h"
#import "UIView+Additions.h"
static const CGFloat RefreshMinY = - 64.f;

NSString *const BaseRefreshViewObserveKeyPath = @"contentOffset";
@implementation MHRefreshHeader

//使点击穿透
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    return nil;
}
+(instancetype)refreshWithScroll:(UIScrollView *)scrollView
{
    MHRefreshHeader *header = [MHRefreshHeader new];
    header.centerX = scrollView.centerX;
    header.y = scrollView.y;
    header.scrollView = scrollView;
    [scrollView.superview addSubview:header];
    return header;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self setupView];
    }
    return self;
}
- (void)setScrollView:(UIScrollView *)scrollView
{
    _scrollView = scrollView;
    //添加监听
    [scrollView addObserver:self forKeyPath:BaseRefreshViewObserveKeyPath options:NSKeyValueObservingOptionNew context:nil];
}

- (void)willMoveToSuperview:(UIView *)newSuperview
{
    if (!newSuperview) {
        [self.scrollView removeObserver:self forKeyPath:BaseRefreshViewObserveKeyPath];
    }
}

-(void)endRefreshing
{
    self.refreshState = MHRefreshStateEndRresh;
}
//初始化图片
- (void)setupView
{
    self.backgroundColor = [UIColor clearColor];
    _refreshImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"loading_1"]];
    NSMutableArray *refreshingImages = [NSMutableArray array];
    for (NSUInteger i = 1; i < 6; i++) {
        UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"loading_%zd", i]];
        [refreshingImages addObject:image];
    }
    _refreshImageView.animationImages = refreshingImages;
    self.bounds = _refreshImageView.bounds;
    [self addSubview:_refreshImageView];
    _refreshImageView.alpha = 0;
    self.refreshState = MHRefreshStateNormal;
}
//刷新状态改变
- (void)setRefreshState:(MHRefreshViewState)refreshState
{
    
    if (refreshState == MHRefreshStateRefreshing) {
        if (self.refreshingBlock) {
            self.refreshingBlock();
        }
        [_refreshImageView startAnimating];
        [UIView animateWithDuration:0.3 animations:^{
            self.scrollView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
        }];
    } else if (refreshState == MHRefreshStateNormal) {
        if (_refreshImageView.isAnimating) {
            [_refreshImageView stopAnimating];
            self.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
        }
    }else if (refreshState == MHRefreshStateEndRresh){
        if (_refreshImageView.isAnimating) {
            [_refreshImageView stopAnimating];
            [UIView animateWithDuration:0.3 animations:^{
                self.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
            }];
        }
    }
}

//改变透明度
-(void)setPullingPercent:(CGFloat)percent
{
    _refreshImageView.alpha = percent;
}

//滑动处理
- (void)updateRefreshHeaderWithOffsetY:(CGFloat)y
{
    if (y > 0) {//防止往上划的时候动图显示出来
        return;
    }
    [self setPullingPercent:(fabs(y) - 20) / (fabs(RefreshMinY) - 20)];
    if (self.refreshState == MHRefreshStateRefreshing) {
        return;
    }
    if (y < RefreshMinY) {
        if(!self.scrollView.isDragging ){
            self.refreshState = MHRefreshStateRefreshing;
        }
    }else{
        if (self.refreshState == MHRefreshStateNormal) {
            return;
        }
        self.refreshState = MHRefreshStateNormal;
    }
    
}
//监听滑动
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (keyPath != BaseRefreshViewObserveKeyPath) return;
    
    [self updateRefreshHeaderWithOffsetY:self.scrollView.contentOffset.y];
}

@end

是不是很简单呀?
然后再看看使用

 _refreshHeader = [MHRefreshHeader refreshWithScroll:_tableView];
    __weak typeof(self) weakSelf = self;
    [_refreshHeader setRefreshingBlock:^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakSelf.refreshHeader endRefreshing];
        });
    }];

只有2步,通过scrollview创建,然后在刷新方法里面结束刷新.给大家提供个思路,有更好的办法欢迎留言交流
github地址

你可能感兴趣的:(iOS自定义下拉刷新控件--保持刷新动画位置不变)