基于lottie的下拉刷新动画封装

基于lottie的下拉刷新动画封装_第1张图片
image.png

分三段动画

第一段pulling动画
手动打开书本,跟随下拉手势距离修改动画播放百分比。

第二段文字跳出
刷新过程中文字跳到出现动效,只播放一次,播放完成后,一直保留到完全结束刷新。

第三段持续翻书动效
刷新过程中,书本翻动动效,可持续轮播或播放一次动画后,自动完成刷新。

上代码:


#import "MJRefreshHeader.h"

NS_ASSUME_NONNULL_BEGIN

@interface DDRefreshLottieHeader : MJRefreshHeader

@property (nonatomic, assign) BOOL isAutoEndRefreshing;   //!< 翻书动效执行一遍后自动收起

@property (nonatomic, assign) BOOL isNeedMoveToTop;   //!<设置ignoredScrollViewContentInsetTop后,为了避免被遮挡 是否需要将刷新控件移到最顶部

/// 模拟手动下拉刷新
/// @param refreshHeader refreshHeader
+ (void)beginLottiePullingRefreshing:(MJRefreshHeader *)refreshHeader;

@end

NS_ASSUME_NONNULL_END


#import "DDRefreshLottieHeader.h"

#import "DDLottieAnimationView.h"

static const CGFloat LottieHeader_loading_originY = 6.0;
static const CGFloat LottieHeader_loading_width  = 90.0;
static const CGFloat LottieHeader_loading_height = 65.0;

@interface DDRefreshLottieHeader()

@property (nonatomic, strong) DDLottieAnimationView *pullingLottieView;
@property (nonatomic, strong) DDLottieAnimationView *refreshTextLottieView;
@property (nonatomic, strong) DDLottieAnimationView *refreshLoopLottieView;
@property (nonatomic, assign) BOOL isRefreshing;

@end

@implementation DDRefreshLottieHeader

#pragma mark - 重写方法
//TODO: 在这里做一些初始化配置(比如添加子控件)
- (void)prepare
{
    [super prepare];
    self.layer.zPosition = -1;
    self.mj_h = LottieHeader_loading_height + 8;
}
//TODO: 在这里设置子控件的位置和尺寸
- (void)placeSubviews
{
    [super placeSubviews];
    [self addSubview:self.refreshTextLottieView];
    [self addSubview:self.pullingLottieView];
    [self addSubview:self.refreshLoopLottieView];
}

- (void)setIsAutoEndRefreshing:(BOOL)isAutoEndRefreshing
{
    self.refreshLoopLottieView.loopAnimation = NO;
}

- (void)setIsNeedMoveToTop:(BOOL)isNeedMoveToTop
{
    _isNeedMoveToTop = isNeedMoveToTop;
}

#pragma mark 模拟下拉刷新状态
+ (void)beginLottiePullingRefreshing:(DDRefreshLottieHeader *)refreshHeader
{
    refreshHeader.pullingPercent = 0.0;
    [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
        refreshHeader.alpha = 1.0;
        refreshHeader.pullingPercent = 1.0;
    } completion:^(BOOL finished) {
        [refreshHeader beginRefreshing];
    }];
}

#pragma mark- 监听拖拽比例(控件被拖出来的比例)
- (void)setPullingPercent:(CGFloat)pullingPercent
{
    if (self.isNeedMoveToTop) {
        self.layer.zPosition = 1024;
    }
    if (pullingPercent <= 0.05) {
        return;
    }
    if ( self.isRefreshing || pullingPercent >= 1.0) {
        self.pullingLottieView.hidden = YES;
        self.refreshLoopLottieView.hidden = NO;
        return;
    }
    self.pullingLottieView.hidden = NO;
    self.refreshLoopLottieView.hidden = YES;
    [super setPullingPercent:pullingPercent];
    CGFloat progressBegin = pullingPercent - 1.0 >= 0 ? 1.0 : pullingPercent;
    self.pullingLottieView.animationProgress = progressBegin;
}

#pragma mark - 监听控件的刷新状态 根据状态做事情
- (void)setState:(MJRefreshState)state
{
    self.isRefreshing = NO;
    MJRefreshCheckState;
    switch (state) {
        case MJRefreshStatePulling: {
            //下拉状态: 监听拖拽比例设置动画效果(控件被拖出来的比例)
        }
            break;
        case MJRefreshStateRefreshing: {
            //刷新状态
            self.isRefreshing = YES;
            self.pullingLottieView.hidden = YES;
            self.refreshLoopLottieView.animationProgress = 0.0;
            [self.refreshTextLottieView play];
            self.refreshLoopLottieView.hidden = NO;
            if (self.isAutoEndRefreshing) {
                [self autoEndRefreshing];
            } else {
                [self.refreshLoopLottieView play];
            }
            break;
        }
        default: {
            if (self.isAutoEndRefreshing) {
                [self autoEndRefreshing];
                weakify(self);
                self.endRefreshingCompletionBlock = ^{
                    strongify(self);
                    if (self.isNeedMoveToTop) {
                        self.layer.zPosition = -1;
                    }
                };
            } else {
                weakify(self);
                [self.refreshLoopLottieView pause];
                self.endRefreshingCompletionBlock = ^{
                    strongify(self);
                    [self initLottieAnimationProgress];
                    if (self.isNeedMoveToTop) {
                        self.layer.zPosition = -1;
                    }
                };
            }
        }
            break;
    }
}

- (void)autoEndRefreshing
{
    weakify(self);
    [self.refreshLoopLottieView playToProgress:0.9 withCompletion:^(BOOL animationFinished) {
        strongify(self);
        [self endRefreshing];
    }];
}

- (void)initLottieAnimationProgress
{
    //初始状态
    [self.pullingLottieView stop];
    [self.refreshTextLottieView stop];
    [self.refreshLoopLottieView pause];
    self.pullingLottieView.hidden = NO;
    self.refreshLoopLottieView.hidden = YES;
}

- (DDLottieAnimationView *)refreshTextLottieView
{
    if (_refreshTextLottieView == nil) {
        _refreshTextLottieView = [DDLottieAnimationView animationNamed:app_lottie_refresh_slogan_json];
        _refreshTextLottieView.frame = CGRectMake((DD_SCREEN_WIDTH - LottieHeader_loading_width) * 0.5,LottieHeader_loading_originY, LottieHeader_loading_width, LottieHeader_loading_height);
        _refreshTextLottieView.loopAnimation = NO;
    }
    return _refreshTextLottieView;
}

- (DDLottieAnimationView *)pullingLottieView
{
    if (_pullingLottieView == nil) {
        _pullingLottieView = [DDLottieAnimationView animationNamed:app_lottie_refresh_book_open_json];
        _pullingLottieView.frame = CGRectMake((DD_SCREEN_WIDTH - LottieHeader_loading_width) * 0.5, LottieHeader_loading_originY, LottieHeader_loading_width, LottieHeader_loading_height);
        _pullingLottieView.loopAnimation = NO;
    }
    return _pullingLottieView;
}

- (DDLottieAnimationView *)refreshLoopLottieView
{
    if (_refreshLoopLottieView == nil) {
        _refreshLoopLottieView = [DDLottieAnimationView animationNamed:app_lottie_refresh_book_flip_json];
        _refreshLoopLottieView.frame = CGRectMake((DD_SCREEN_WIDTH - LottieHeader_loading_width) * 0.5, LottieHeader_loading_originY, LottieHeader_loading_width, LottieHeader_loading_height);
        _refreshLoopLottieView.loopAnimation = YES;
    }
    return _refreshLoopLottieView;
}

@end

你可能感兴趣的:(基于lottie的下拉刷新动画封装)