美文网首页
iOS自定义下拉刷新控件--保持刷新动画位置不变

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

作者: 徐老茂 | 来源:发表于2018-04-18 16:39 被阅读579次

    说到下拉刷新我想都会想到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/UIKit.h>
    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<NSString *,id> *)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自定义下拉刷新控件--保持刷新动画位置不变

          本文链接:https://www.haomeiwen.com/subject/zogvkftx.html