歌颂祖国,简单的图片消失动画

1,957 阅读3分钟

歌颂祖国!用OC简单的写了一个小demo。

屏幕录制2021-10-04 下午4.11.16.gif

步骤一、创建图片切片存储对象

@interface** KDSClipImageModel : NSObject


//保存切图位置
@property (nonatomic,assign) CGRect rect;
//切片image
@property (nonatomic,strong) UIImage * image;
//缩放宽度
@property (nonatomic,assign) CGFloat scaleW;
//缩放高度
@property (nonatomic,assign**) CGFloat scaleH;
//imageView
@property (nonatomic,strong) UIImageView * imageView;



@end

步骤二、管理类

1、管理类

//定时器,用来发射粒子
static dispatch_source_t timer;
//因为管理类用的是类方法,所以这里用static修饰了一个布尔值,来保存切片小图是否可以消失
static bool isCanDismiss = true;

@interface KDSClipImageTool : NSObject

2、一张整图生成切图

//将一张图片切成N个小图,imgae:原图,row:行数,column:列数,rect是要展示的view的rect,
这样可以根据image和rect的大小进行缩放。
+ (NSMutableArray *)clipAllCellImagesWithImage:(UIImage *)image row:(NSInteger)row column:(NSInteger)column rect:(CGRect)rect

{

    NSMutableArray * saveCellImagesArr = @[].mutableCopy;

    CGFloat imageWidth = image.size.width;

    CGFloat imageHeight = image.size.height;
    //小图的宽度
    CGFloat width = (imageWidth / column);
    //小图的高度
    CGFloat height = (imageHeight / row);
    //缩放宽度
    CGFloat rw = (rect.size.width / imageWidth);
    //缩放高度
    CGFloat rh = (rect.size.height / imageHeight);

    for (int i = 0; i < column; i++) {

        for (int j = 0; j < row; j++) {

            CGRect imageRect = CGRectMake(width * i, height * j, width, height);
            //切小图
            UIImage * cellImage = [self clipImageWithAllImage:image rect:imageRect];
            //保存数据
            KDSClipImageModel * model = [[KDSClipImageModel alloc] init];

            model.image = cellImage;

            model.scaleW = rw;

            model.scaleH = rh;
            //这里计算小切图实际的位置坐标
            CGRect imageRRect = CGRectMake(width * rw * i, height * rh * j, width * rw, height * rh);

            model.imageView = [[UIImageView alloc] initWithFrame:imageRRect];

            model.imageView.image = cellImage;

            model.rect = imageRRect;

            [saveCellImagesArr addObject:model];

        }

    }

    return saveCellImagesArr;

}

//切小图逻辑
+ (UIImage *)clipImageWithAllImage:(UIImage *)image rect:(CGRect)rect

{

    CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, rect);

    UIImage * imageResult = [UIImage imageWithCGImage:imageRef];

    CGImageRelease(imageRef);

    return imageResult;

}

3、展示切图组无序排列

//展示大图片前将小图先随机打乱顺序,然后进行重排复原,最后进行粒子消失动画
+ (void)showImageModels:(NSMutableArray <KDSClipImageModel *>*)clipImageModels pushView:(UIView *)pushView canDismiss:(void(^)(void))dismissBlock

{

    isCanDismiss = true;

    //随机排序
    NSArray *tempClipImageModels = [clipImageModels sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {

        return (arc4random_uniform(2) == 0);

    }];

    

    NSInteger index = 0;
    //重置乱序下的小图
    for (KDSClipImageModel * clipImageModel **in** tempClipImageModels) {

        KDSClipImageModel * imageModel = clipImageModels[index];

        clipImageModel.imageView.frame = imageModel.rect;

        index ++;

    }

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //图片复原
        for (KDSClipImageModel * clipImageModel in tempClipImageModels) {

            [UIView animateWithDuration:0.3 animations:^{

                clipImageModel.imageView.frame = clipImageModel.rect;

            } completion:^(BOOL finished) {

                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    //这里只进行一次消失动画,所以用static修饰isCanDismiss 来执行dismiss
                    if (isCanDismiss == true) {

                        if (dismissBlock) {

                            dismissBlock();

                        }

                        isCanDismiss = false;

                    }

                });

            }];

        }

    });

}

4、粒子消失


//定时器下定时创建粒子发射器发射粒子,粒子的CGImage为小切图的image内容
+ (void)setupEmitterWithClipImageModels:(NSMutableArray <KDSClipImageModel *>*)clipImageModels pushView:(UIView *)pushView{

    
    //随机创建10个粒子发射器
    NSInteger radomNum = 10;

    dispatch_queue_t queue = dispatch_get_main_queue();
    
    //初始化定时器
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 0.05 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);

    dispatch_source_set_event_handler(timer, ^{

        if (clipImageModels.count <= 0) {

            dispatch_suspend(timer);

        } else {
            
            //随机获取 KDSClipImageModel 进行粒子释放
            for (int i = 0; i < radomNum; i++) {

                NSInteger index = arc4random() % clipImageModels.count;

                KDSClipImageModel * model = clipImageModels[index];

                [self createCAEmitterCellWithImage:model pushView:pushView];
                
                //移除 KDSClipImageModel 
                [clipImageModels removeObject:model];

            }

        }

    });

    dispatch_resume(timer);

}


//创建粒子发射器
+ (void)createCAEmitterCellWithImage:(KDSClipImageModel *)model pushView:(UIView *)pushView

{

    CAEmitterLayer *emitter = [[CAEmitterLayer alloc]init];
    emitter.preservesDepth = YES;
    
    CAEmitterCell *cell = [[CAEmitterCell alloc]init];
    //因为是粒子性,所以一般是设置具体参数值及设置参数的波动范围。
    cell.velocity = 150;
    cell.velocityRange = 100;
    cell.scale = 1 * model.scaleW;
    cell.scaleRange = 1 * model.scaleW;
    cell.emissionLongitude = -M_PI_2;
    cell.emissionRange = M_PI_2 / 4;
    cell.lifetime = 3;
    cell.lifetimeRange = .5;
    cell.spin = M_PI_2;
    cell.spinRange = M_PI_2 / 2;
    cell.birthRate = 1;
    emitter.emitterPosition = CGPointMake(model.rect.origin.x, model.rect.origin.y);
    //这里设置粒子的内容,即小切图的内容
    cell.contents = ( __bridge id _Nullable )(model.image.CGImage);
    emitter.emitterCells = @[cell];
    
    //移除所有相关数据
    [pushView.layer addSublayer:emitter];
    
    [model.imageView removeFromSuperview];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        [emitter removeFromSuperlayer];

    });

}

步骤三、展示控件类


#import "KDSClipImageView.h"

#import "KDSClipImageTool.h"

#import "KDSClipImageModel.h"



@interface KDSClipImageView()



@property (nonatomic,strong) NSMutableArray * saveClipImages;




@end




@implementation** KDSClipImageView




- (void)clipImagesCanDismiss:(void(^)(void))disMissBlock

{

    if (!self.image) {

        return;

    }
    
    //获取self的rect
    [self layoutIfNeeded];
    
    //获取小切图数组 这里是30 * 45个
    self.saveClipImages = [KDSClipImageTool clipAllCellImagesWithImage:self.image row:30 column:45 rect:self.bounds];

    for (KDSClipImageModel * imageModel in self.saveClipImages) {

        [self addSubview:imageModel.imageView];

    }

    [self showCanDismiss:disMissBlock];

}

- (void)showCanDismiss:(void(^)(void))disMissBlock

{

    @weakify(self);
    进行展示后进行消失动画
    [KDSClipImageTool showImageModels:self.saveClipImages pushView:self canDismiss:^{

        @strongify(self);

        if (disMissBlock) {

            disMissBlock();

        }

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

            @strongify(self);

            [self dismiss];

        });

    }];

}

- (void)dismiss

{

    //消失动画
    [KDSClipImageTool setupEmitterWithClipImageModels:self.saveClipImages pushView:self];

}

步骤四、初始化


    //国旗背景图
    UIImageView * gqImageView = [[UIImageView alloc] init];

    gqImageView.contentMode = UIViewContentModeScaleAspectFit;

    gqImageView.hidden = YES;

    gqImageView.image = [UIImage imageNamed:@"gq"];
    
    //抗美援朝英雄图
    UIImage * image = [UIImage imageNamed:@"kmyc"];

    KDSClipImageView * imageBaseView = [[KDSClipImageView alloc] init];

    [imageBaseView addSubview:gqImageView];

    [gqImageView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.edges.equalTo(imageBaseView);

    }];

    imageBaseView.image = image;

    [self addSubview:imageBaseView];

    CGFloat imageViewWidth = image.size.width < self.width ?: self.width;

    [imageBaseView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.center.equalTo(self).offset(0);

        make.width.mas_equalTo(imageViewWidth);

        make.height.mas_equalTo((imageViewWidth) * (image.size.height   image.size.width));

    }];

    //开始显示,显示动画完后即将消失时将国旗背景图显示
    [imageBaseView clipImagesCanDismiss:^{

        gqImageView.hidden = NO;

    }];

代码拙劣,大神勿喷。