//
// 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
网友评论