美文网首页
iOS实现爆炸动画效果

iOS实现爆炸动画效果

作者: 扶兮摇兮 | 来源:发表于2020-04-21 19:40 被阅读0次
    //
    //  UIView+animation.m
    //  BoomAnimation
    //
    //  Copyright © 2019年 van. All rights reserved.
    //
    
    #import "UIView+animation.h"
    #import <objc/runtime.h>
    #include<stdio.h>
    
    #define square 65
    
    @implementation UIView (animation)
    
    - (void)boomWithTileSize:(CGSize)size inDiameter:(CGFloat)diameter {
        
        UIGraphicsBeginImageContext(self.bounds.size);
        [[UIColor clearColor] setFill];
        [[UIBezierPath bezierPathWithRect:self.bounds] fill];
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        [self.layer renderInContext:ctx];
        
        UIImage *screenshotImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        UIView* animationView = [[UIView alloc] initWithFrame:self.frame];
        [self.superview addSubview:animationView];
        objc_setAssociatedObject(self, @"boomAnimationView", animationView, OBJC_ASSOCIATION_RETAIN);
        
        NSInteger maxX = floor(screenshotImage.size.width / size.width);
        NSInteger maxY = floor(screenshotImage.size.height / size.height);
        for (int i=0; i<maxX; i++) {
            for (int j = 0; j<maxY; j++) {
                @autoreleasepool {
                   
                    CALayer *rootLayer = [[CALayer alloc] init];
                    rootLayer.frame = CGRectMake(i*size.width, (maxY-j-1)*size.height, size.width, size.height);
                    [self addBackgroundLayer:@[@0, @0, @(-0.1), @(M_PI), @0, @0, @0] rootLayer:rootLayer];
                    
                    CALayer *layer = [[CALayer alloc] init];
                    layer.frame = CGRectMake(i*size.width, (maxY-j-1)*size.height, size.width, size.height);
                    layer.frame = rootLayer.bounds;
                    CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
                                                                          size.width,
                                                                          size.height,
                                                                          8,
                                                                          0,
                                                                          CGImageGetColorSpace(screenshotImage.CGImage),kCGImageByteOrderDefault | kCGImageAlphaPremultipliedFirst);
                    CGContextTranslateCTM(offscreenContext, -i*size.width, -j*size.height);
                    CGContextDrawImage(offscreenContext, CGRectMake(0, 0, screenshotImage.size.width, screenshotImage.size.height), screenshotImage.CGImage);
                    CGImageRef imageRef = CGBitmapContextCreateImage(offscreenContext);
                    layer.contents = CFBridgingRelease(imageRef);
                    CGContextRelease(offscreenContext);
                    layer.backgroundColor = [UIColor blackColor].CGColor;
                    //根据参数对CALayer进行偏移和旋转Transform
                    CATransform3D transform = CATransform3DMakeTranslation(0, 0, 0.1);
                    transform = CATransform3DRotate(transform, 0, 0, 0, 0);
                    //设置transform属性并把Layer加入到主Layer中,这里的transform描述了layer所在的位置和形变等
                    layer.transform = transform;
                    [rootLayer addSublayer:layer];
                    [animationView.layer addSublayer:rootLayer];
                }
            }
        }
        
        animationView.backgroundColor = [UIColor grayColor];
        
        for (CALayer *shape in animationView.layer.sublayers) {
            
            @autoreleasepool {
                
    //            CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    //            UIBezierPath *path = [UIBezierPath bezierPath];
    //            [path moveToPoint:shape.position];
    //            [path addLineToPoint:[self getEndPoint:shape]];
    //            positionAnimation.path = path.CGPath;
                
                CGPoint endP = [self getEndPoint:shape];
                CAKeyframeAnimation *transformAnimation = [CAKeyframeAnimation animationWithKeyPath:@"sublayerTransform"];
                NSMutableArray *values = [NSMutableArray array];
                float angle = [self getRandRotateRangeValue:0.5 baseValue:0];
                int frames = MAX(shape.bounds.size.width, shape.bounds.size.height) / 2;
                NSArray *parm = [self getRotateAxis];
               
                NSArray *points = [self getTransformTranslateLayer:shape layerCoordinate:endP frame:frames];
                for (int i = 0; i < frames; i++) {
                NSArray *coordinateArr = points[i];
                CATransform3D transformRotate = CATransform3DMakeRotation(-angle, [[parm objectAtIndex:0] floatValue], [[parm objectAtIndex:1] floatValue], [[parm objectAtIndex:2] floatValue]);
                CATransform3D transformTranslate = CATransform3DMakeTranslation([[coordinateArr objectAtIndex:0] floatValue], [[coordinateArr objectAtIndex:1] floatValue], [[coordinateArr objectAtIndex:2] floatValue]);
                CATransform3D transform = CATransform3DConcat(transformRotate, transformTranslate);
                [values addObject:[NSValue valueWithCATransform3D:transform]];
                angle += [self getRandRotateRangeValue:0.06 baseValue:0];
                }
                transformAnimation.values = values;
                CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
                animationGroup.repeatCount = 1;
                animationGroup.animations = @[transformAnimation];
                animationGroup.duration = 1.0;
                animationGroup.delegate = self;
                [shape addAnimation:animationGroup forKey:@"handAnimation"];
            }
        }
    }
    
    - (NSArray *)getTransformTranslateLayer:(CALayer *)layer layerCoordinate:(CGPoint)layerPoint frame:(NSInteger)frame{
        
        NSMutableArray *totalPoints = [NSMutableArray array];
        CGPoint centerP = self.superview.center;
        CGFloat x1 = layer.frame.origin.x + layer.frame.size.width  *0.5;
        CGFloat y1 = layer.frame.origin.y + layer.frame.size.height *0.5;
        CGFloat x2 = centerP.x;
        CGFloat y2 = centerP.y;
        
        CGFloat x_distance = fabs(layerPoint.x - x1);
        CGFloat y_distance = fabs(layerPoint.y - y1);
        CGFloat x_var = fabs(x_distance)/frame; // x方向上的单位变量
        CGFloat y_var = fabs(y_distance)/frame; // y方向上的单位变量
        int i = 0;
        while (i < frame) {
            // 存放x,y,z轴上分别t要平移的坐标分量
            NSMutableArray *coordinateArr = [NSMutableArray array];
            
            CGFloat objx = 0;
            CGFloat objy = 0;
            CGFloat objz = 0;
            
            // 第一象限
            if (x1 <= x2 && y1 < y2) {
                
                objx =  -i*x_var;
                objy =  -i*y_var;
            }
            
            // 第二象限
            if (x1 > x2 && y1 <= y2) {
                
                objx = i*x_var;
                objy = -i*y_var;
            }
            
            // 第三象限
            if (x1 < x2 && y1 >= y2) {
                
                objx = -i*x_var;
                objy = i*y_var;
            }
            
            // 第四象限
            if (x1 > x2 && y1 >= y2) {
                
                objx = i*x_var;
                objy = i*y_var;
            }
            
            objz = sqrt(pow(objx, 2) + pow(objy, 2))*((float)rand()/(float)RAND_MAX * 3.0);
            [coordinateArr addObject:@(objx)];
            [coordinateArr addObject:@(objy)];
            [coordinateArr addObject:@(objz)];
            
            [totalPoints addObject:coordinateArr];
            i++;
        }
    
        return totalPoints;
    }
    
    - (CGFloat)getRandRotateRangeValue:(CGFloat)value baseValue:(CGFloat)baseValue{
        return  (float)rand()/(float)RAND_MAX * 2 * value + baseValue;
    }
    
    - (NSArray *)getRotateAxis{
        
        NSMutableArray *parmArr = [NSMutableArray array];
        NSArray *optionNumber = @[@(-1),@(0),@(1)];
        int i = 0;
        while (i<3) {
            
        int index = [self getRandOneRandThree];
        [parmArr addObject:optionNumber[index]];
            i++;
        }
        return parmArr;
        
    }
    - (int)getRandOneRandThree{
        return arc4random_uniform(3);
    }
    - (void)firstAddLayer:(NSArray*)params rootLayer:(CALayer *)rootLayer{
      
        CALayer *layer = [[CALayer alloc] init];
        layer.backgroundColor = [UIColor blueColor].CGColor;
        layer.bounds = CGRectMake(0, 0, square, square);
        layer.position = CGPointMake(CGRectGetMidX(rootLayer.bounds), CGRectGetMidY(rootLayer.bounds));
        //根据参数对CALayer进行偏移和旋转Transform
        CATransform3D transform = CATransform3DMakeTranslation([[params objectAtIndex:0] floatValue], [[params objectAtIndex:1] floatValue], [[params objectAtIndex:2] floatValue]);
        
        transform = CATransform3DRotate(transform, [[params objectAtIndex:3] floatValue], [[params objectAtIndex:4] floatValue], [[params objectAtIndex:5] floatValue], [[params objectAtIndex:6] floatValue]);
        //设置transform属性并把Layer加入到主Layer中,这里的transform描述了layer所在的位置和形变等
        layer.transform = transform;
        [rootLayer addSublayer:layer];
    }
    
    - (void)addBackgroundLayer:(NSArray *)params rootLayer:(CALayer *)rootLayer{
        
        CALayer *bgLayer = [[CALayer alloc] init];
        bgLayer.backgroundColor = [UIColor blackColor].CGColor;
        bgLayer.contentsScale = [UIScreen mainScreen].scale;
        bgLayer.bounds = CGRectMake(0, 0, square, square);
        bgLayer.position = CGPointMake(CGRectGetMidX(rootLayer.bounds), CGRectGetMidY(rootLayer.bounds));
        
        //根据参数对CALayer进行偏移和旋转Transform
        CATransform3D transform = CATransform3DMakeTranslation([[params objectAtIndex:0] floatValue], [[params objectAtIndex:1] floatValue], [[params objectAtIndex:2] floatValue]);
        
        transform = CATransform3DRotate(transform, [[params objectAtIndex:3] floatValue], [[params objectAtIndex:4] floatValue], [[params objectAtIndex:5] floatValue], [[params objectAtIndex:6] floatValue]);
        //设置transform属性并把Layer加入到主Layer中,这里的transform描述了layer所在的位置和形变等
        bgLayer.transform = transform;
        [rootLayer addSublayer:bgLayer];
    }
    
    - (CGFloat)productRandNumberWithRadio:(CGFloat)radio{
        
        return (float)rand()/(float)RAND_MAX*radio + radio;
    }
    // 计算layer所在直线与X轴的夹角
    - (float)calculateAngle:(CALayer *)layer{
        
        CGPoint centerP = self.superview.center;
        CGFloat x1 = layer.frame.origin.x + layer.frame.size.width  *0.5;
        CGFloat y1 = layer.frame.origin.y + layer.frame.size.height *0.5;
        CGFloat x2 = centerP.x;
        CGFloat y2 = centerP.y;
        
        CGFloat y_var = fabs(y2-y1);
        CGFloat x_var = fabs(x2-x1);
        return atanf(y_var/x_var);
    }
    
    // layer运动路径
    - (CGPoint)getEndPoint:(CALayer *)layer{
        
        CGPoint centerP = self.superview.center;
        CGFloat x1 = layer.frame.origin.x + layer.frame.size.width  *0.5;
        CGFloat y1 = layer.frame.origin.y + layer.frame.size.height *0.5;
        CGFloat x2 = centerP.x;
        CGFloat y2 = centerP.y;
        CGFloat r = self.superview.bounds.size.height*0.5 + 100;
       
       NSArray *points = [self getInsertPointBetweenCircleAndLineX1:x1 Y1:y1 X2:x2 Y2:y2 circleX:x2 circleY:y2 radius:r];
        // 第一象限
        if (x1 <= x2 && y1 < y2) {
    
            for (NSValue *value in points) {
                CGPoint valueP = [value CGPointValue];
                if (valueP.x < x2) {
                    return valueP;
                }
            }
        }
    
        // 第二象限
        if (x1 > x2 && y1 <= y2) {
            
            for (NSValue *value in points) {
                CGPoint valueP = [value CGPointValue];
                if (valueP.x > x2) {
                    return valueP;
                }
            }
        }
    
        // 第三象限
        if (x1 < x2 && y1 >= y2) {
            
            for (NSValue *value in points) {
                CGPoint valueP = [value CGPointValue];
                if (valueP.x < x2) {
                    return valueP;
                }
            }
        }
    
        // 第四象限
        if (x1 > x2 && y1 >= y2) {
               
            for (NSValue *value in points) {
                CGPoint valueP = [value CGPointValue];
                if (valueP.x > x2) {
                    return valueP;
                }
            }
        }
        
        return CGPointZero;
    }
    /**
      * 求圆和直线之间的交点
      * 直线方程:y = kx + b
      * 圆的方程:(x - m)² + (x - n)² = r²
      * x1, y1 = 线坐标1, x2, y2 = 线坐标2, m, n = 圆坐标, r = 半径
      */
    - (NSArray *)getInsertPointBetweenCircleAndLineX1:(CGFloat)x1 Y1:(CGFloat) y1 X2:(CGFloat) x2 Y2:(CGFloat)y2 circleX:(CGFloat)m circleY:(CGFloat)n radius:(CGFloat)r {
        
        NSArray *kbArr = [self binaryEquationGetKBX1:x1 Y1:y1 X2:x2 Y2:y2];
        CGFloat k = [kbArr[0] floatValue];
        CGFloat b = [kbArr[1] floatValue];
    
        CGFloat aX = 1 + k * k;
        CGFloat bX = 2 * k * (b - n) - 2 * m;
        CGFloat cX = m * m + (b - n) * (b - n) - r * r;
        
        NSMutableArray *insertPoints = [NSMutableArray array];
        NSArray *xArr = [self quadEquationGetX:aX bX:bX cx:cX];
        
        for (NSNumber *obj in xArr) {
            CGFloat y = k *obj.floatValue + b;
            [insertPoints addObject:[NSValue valueWithCGPoint:CGPointMake(obj.floatValue, y)]];
        }
        
        return insertPoints;
    }
    /**
     * 求二元一次方程的系数
     * y1 = k * x1 + b => k = (y1 - b) / x1
     * y2 = k * x2 + b => y2 = ((y1 - b) / x1) * x2 + b
     */
    - (NSArray *)binaryEquationGetKBX1:(CGFloat)x1  Y1:(CGFloat)y1 X2:(CGFloat)x2 Y2:(CGFloat)y2 {
        CGFloat k = (y1 - y2) / (x1 - x2);
        CGFloat b = (x1 * y2 - x2 * y1) / (x1 - x2);
        
        return @[@(k), @(b)];
    }
    /**
     * 一元二次方程求根
     * ax² + bx + c = 0
     */
    - (NSArray *)quadEquationGetX:(CGFloat)a bX:(CGFloat)b cx:(CGFloat)c{
        
        NSMutableArray *xArr = [NSMutableArray array];
        CGFloat result = pow(b, 2) - 4 * a * c;
        if (result > 0) {
            CGFloat insertPointX1 = (-b + sqrt(result)) / (2 * a);
            CGFloat insertPointX2 = (-b - sqrt(result)) / (2 * a);
            [xArr addObject:@(insertPointX1)];
            [xArr addObject:@(insertPointX2)];
        } else if (result == 0) {
            CGFloat insertPointX = -b / (2 * a);
            [xArr addObject:@(insertPointX)];
        }
        return xArr;
    }
    
    - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
        UIView* animationView = (UIView*)objc_getAssociatedObject(self, @"boomAnimationView");
        if (animationView == nil) {
            return;
        }
        objc_removeAssociatedObjects(animationView);
        [animationView removeFromSuperview];
    }
    
    @end
    
    
    

    相关文章

      网友评论

          本文标题:iOS实现爆炸动画效果

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