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/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地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 黑夜将尽, 黎明将来。
    秋风劲劲阅读 158评论 1 4
  • 旅行就是拿到了一场艳遇的车票。 我回忆起了《雪国》。开始时也是在列车上,驹子热情地同扳道工交谈。于是,开始了一场埋...
    冰眉铁面阅读 308评论 0 0
  • 有人说过“生命从头到尾都是一场浪费,你需要判断的是,这次浪费是否值得”。我一直对这句话理解的都不是那么深刻,如果都...
    宋大宝不饱阅读 428评论 1 3