iOS-自定义MJRefresh下拉刷新动画

来源:互联网 发布:键盘反应速度调节软件 编辑:程序博客网 时间:2024/05/19 06:14

前段时间发现天虹旗下”红领巾”app的下拉刷新动画挺有趣,重新仿写了一个;见动画效果;

刷新效果如图


代码实现如下

MJRefreshGifHeader继承自MJ中的MJRefreshGifHeader#import "MJRefreshGifHeader.h"@interface CustomRefreshGifHeader : MJRefreshGifHeader/** 设置state状态下的动画图片images 动画持续时间duration*/- (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state;- (void)setImages:(NSArray *)images forState:(MJRefreshState)state;@end

#import "CustomRefreshGifHeader.h"#define WIDTH   [UIScreen mainScreen].bounds.size.width@interface CustomRefreshGifHeader()//一直左滑动的动画图片@property (nonatomic, strong) UIView *bgView;//顶部的图片@property (nonatomic, strong) UIImageView *topImage;//自定义的刷新提示状态@property (nonatomic, strong) UILabel *customStatusLable;//跑动的ImageV@property (nonatomic, strong) UIImageView *customImageV;//重写父类@property (strong, nonatomic) NSMutableDictionary *stateImages;//重写父类@property (strong, nonatomic) NSMutableDictionary *stateDurations;@end@implementation CustomRefreshGifHeader#pragma mark - 懒加载- (UIImageView *)topImage {    if (!_topImage) {        [self addSubview:_topImage =[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"顶部图片"]]];        _topImage.frame = CGRectMake(0, -360, WIDTH, 360);        _topImage.contentMode = UIViewContentModeScaleAspectFit;    }    return _topImage;}- (UIView *)bgView {    if (!_bgView) {        [self addSubview:_bgView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, WIDTH * 2, 60)]];        for (int i = 0; i < 2; i ++) {            UIImageView *image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"refreshbg"]];            image.frame = CGRectMake(WIDTH * i, 0, WIDTH, 60);            image.contentMode = UIViewContentModeScaleAspectFill;            [_bgView addSubview:image];        }    }    return _bgView;}- (UIImageView *)customImageV {    if (!_customImageV ) {        [self addSubview:_customImageV = [[UIImageView alloc] init]];    }    return _customImageV;}- (NSMutableDictionary *)stateImages {    if (!_stateImages) {        self.stateImages = [NSMutableDictionary dictionary];    }    return _stateImages;}- (NSMutableDictionary *)stateDurations {    if (!_stateDurations) {        self.stateDurations = [NSMutableDictionary dictionary];    }    return _stateDurations;}#pragma mark - 公共方法//重写动画实现- (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state {    if (images == nil) return;    self.stateImages[@(state)] = images;    self.stateDurations[@(state)] = @(duration);    /* 根据图片设置控件的高度 */    UIImage *image = [images firstObject];    if (image.size.height > self.mj_h) {        self.mj_h = image.size.height;    }}- (void)setImages:(NSArray *)images forState:(MJRefreshState)state {    [self setImages:images duration:images.count * 0.1 forState:state];}#pragma mark - 实现父类的方法//初始化操作- (void)prepare {    [super prepare];    self.labelLeftInset = 20;    [self bgView];    [self topImage];    self.lastUpdatedTimeLabel.hidden = YES;    self.gifView.hidden = YES;    self.stateLabel.hidden = YES;    [self bringSubviewToFront:self.customStatusLable];    [self bringSubviewToFront:self.customImageV];}///重写MJ百分比- (void)setPullingPercent:(CGFloat)pullingPercent {    [super setPullingPercent:pullingPercent];    //如果拖动的百分比大于1则显示为1    if (self.scrollView.dragging) {        if (pullingPercent >= 1) {            pullingPercent = 0.9999;        }    }    self.customImageV.frame = CGRectMake(WIDTH * 0.2  * pullingPercent ,  60 * (1 - pullingPercent), 60 * pullingPercent, 60 * pullingPercent);    if (self.bgView.layer.animationKeys.count == 0) {        [self.bgView.layer addAnimation:[self creatAnimation] forKey:@"animation"];    }    NSArray *images = self.stateImages[@(MJRefreshStateIdle)];    if (self.state != MJRefreshStateIdle || images.count == 0) return;    [self.customImageV stopAnimating];    NSUInteger index =  images.count * pullingPercent;    if (index >= images.count) index = images.count - 1;    self.customImageV.image = images[index];    [self layoutSubviews];}//新的动画图片frame不在根据placeSubviews调整, 而是在拖动百分比中设置- (void)placeSubviews {    [super placeSubviews];}- (void)setState:(MJRefreshState)state {    MJRefreshCheckState#pragma mark    无论是状态还是百分比发生变化, 均检测一次是否有动画; 若没有,添加    if (self.bgView.layer.animationKeys.count == 0) {        [self.bgView.layer addAnimation:[self creatAnimation] forKey:@"animation"];    }    //自定义位置的提示刷新状态始终跟父类的保持一致    self.customStatusLable.text = self.stateLabel.text;    if (state == MJRefreshStatePulling || state == MJRefreshStateRefreshing) {        NSArray *images = self.stateImages[@(state)];        if (images.count == 0) return;        [self.customImageV stopAnimating];        if (images.count == 1) { // 单张图片            self.customImageV.image = [images lastObject];        } else { // 多张图片            self.customImageV.animationImages = images;            self.customImageV.animationDuration = [self.stateDurations[@(state)] doubleValue];            [self.customImageV startAnimating];        }    } else if (state == MJRefreshStateIdle) {        [self.customImageV stopAnimating];    }}//主要效果就是实现当刷新状态完成时仍然能够保持动画完成.- (void)endRefreshing {    __weak CustomRefreshGifHeader *weakSelf = self;    [UIView animateWithDuration:1.3f animations:^{        weakSelf.customImageV.frame = CGRectMake(WIDTH + 10, 60 * 0.00001, 60 * 0.9999, 60 * 0.9999);    } completion:^(BOOL finished) {        //向右跑动的动画当跑出屏幕后就置位zero        weakSelf.customImageV.frame = CGRectZero;        dispatch_async(dispatch_get_main_queue(), ^{            weakSelf.state = MJRefreshStateIdle;            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{                [weakSelf.bgView.layer removeAllAnimations];            });        });    }];}#pragma mark    Animation- (CABasicAnimation *)creatAnimation {    self.bgView.layer.anchorPoint = CGPointMake(0, 0);    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];    animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];    animation.toValue = [NSValue valueWithCGPoint:CGPointMake(-WIDTH, 0)];    animation.repeatCount = MAXFLOAT;    animation.duration = 20;    animation.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionLinear];    animation.removedOnCompletion = NO;    animation.fillMode = kCAFillModeBackwards;    return animation;}- (UILabel *)customStatusLable {    if (!_customStatusLable) {        [self addSubview:_customStatusLable  = [[UILabel alloc] initWithFrame:CGRectMake(0, 40, WIDTH, 20)]];        _customStatusLable.font = [UIFont systemFontOfSize:10];        _customStatusLable.textAlignment = NSTextAlignmentCenter;        _customStatusLable.textColor = [UIColor darkGrayColor];    }    return _customStatusLable;}- (void)dealloc {    NSLog(@"%@------------dealloc", self.class);}@end

使用时只需将自定义的类拖进工程即可,跟原本MJ使用方法相同.详见demo


Demo地址

0 0
原创粉丝点击