您的位置:首页 > 其它

教你做泡泡动画

2016-03-26 19:37 316 查看
以下文章版权归叶景天博客所有`

  老规矩,效果图如下所示:

  


  刚开始我看这个动画的时候真的被震撼到了,无论用什么来实现都觉得非常非常得难,用粒子发射器,动力框架,感觉都做不出来.只觉得其中的算法肯定及其复杂又复杂, 然而,越是高级的程序员越是能用"懒惰的方法"实现复杂的功能,没错,这个动画只是封装了一个imageView的子类而已,并没有想象当中的那么复杂,我把动画实现的渲染图放到下面,你看了也绝对会恍然大悟:

  


  是否瞬间觉得这个动画简单了许多,我以前好像提到过,看似高级的动画,其实基本都是由几个CoreAnimation的叠加形成的,接下来我们便分析一下这个动画是怎么叠加做成的?

  分解:

  先不要看那么多的气泡,但从一个气泡上面进行分析:

  1.从渲染图上可以看出,一个气泡上面用了大量的随机函数,气泡的大小,气泡的透明度,贝塞尔曲线的变化,所以封装的过程当中必然要先写一个随机的方法,方便调用;

  2.贝塞尔曲线变化的规律,从渲染图可以看出,贝塞尔曲线的起点是不变的,变的只是有三个点,左边的控制点,和有右边的控制点,以及贝塞尔曲线的终点;

  3.让气泡沿着贝塞尔曲线行走,用关键帧动画是最理想不过的了,关键帧动画不仅能够制定它的key数组,还能给他制定一条路径,让气泡沿着这条路径行走

  4.气泡走到贝塞尔曲线终点的时候,我们也可以看到它有一个爆破的效果,因此关键帧动画必然有一个delegate方便在动画结束的时候执行爆破动画

  5.动画爆破的效果主要有两个动作 放大->消失 放大之后还要消失,所以用UIView封装的transitionWithView来做这个效果在得知放大之后(动画结束之后),将泡泡imageView从父视图中移除掉;

  单个泡泡的分析完毕,那么一群泡泡的分析就简单多了,就只有一个特点,随机在屏幕的中间X轴的位置上产生一个新的泡泡!

  分析完毕之后就可以写代码了,整体的代码封装在一个集成了UIImageView的BubbleImageView上面

  首先是随机取一个从 min 到 max的一个浮点值函数的写法  

- (CGFloat)makeRandomNumberFromMin:(CGFloat)min toMax: (CGFloat)max

{

NSInteger precision = 100;

CGFloat subtraction = ABS(max - min);

subtraction *= precision;

CGFloat randomNumber = arc4random() % ((int)subtraction+1);

randomNumber /= precision;

randomNumber += min;

//返回结果

return randomNumber;

}

以下是BubbleImageView的属性列表:

@interface BubbleImageView ()

@property (nonatomic, assign)CGFloat maxHeight; //贝塞尔曲线的最大高度

@property (nonatomic, assign)CGFloat maxWidth; //贝塞尔曲线的最大宽度

@property (nonatomic, assign)BubblePathType pathType;

//每一次动画执行的最大高度和最大宽度

@property (nonatomic, assign)CGFloat nowMaxHeight;

@property (nonatomic, assign)CGFloat nowMaxWidth;

@property (nonatomic, assign)CGPoint originPoint;

@property (nonatomic, assign)CGRect originFrame;

//贝塞尔曲线的渲染layer;

//@property (nonatomic, strong)CAShapeLayer *shapeLayer;

@end

接着是BubbleImageView的初始化方法

- (instancetype)initWithMaxHeight:(CGFloat) maxHeight maxWidth: (CGFloat)maxWidth maxFrame:(CGRect)frame andSuperView: (UIView *)superView

{

self = [[BubbleImageView alloc]initWithImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"bubble" ofType:@"png"]]];

if (self) {

self.originFrame = frame;

self.frame = [self getRandomFrameWithFrame:frame];

self.originPoint = self.frame.origin;

[superView addSubview:self];

self.maxHeight = maxHeight;

self.maxWidth = maxWidth;

self.alpha = [self makeRandomNumberFromMin:0.5 toMax:1];

[self getRandomBubbleType];

[self getRandomPathWidthAndHeight];

[self setUpBezierPath];

}

return self;

}

//三个随机函数的方法如下面所示

//这个随机函数是为了获得,泡泡是先往哪个方向走,总共有两种方向,第一种是先左后右,第二种是先右后左

//如手稿所示



- (void)getRandomBubbleType

{

if (arc4random() %2 ==1) {

self.pathType = BubblePathTypeLeft;

}else{

self.pathType = BubblePathTypeRight;

}

}

- (void)getRandomPathWidthAndHeight {

self.nowMaxHeight = [self makeRandomNumberFromMin:self.maxHeight / 2 toMax:self.maxHeight];

self.nowMaxWidth = [self makeRandomNumberFromMin:0 toMax:self.maxWidth];

}

- (CGRect)getRandomFrameWithFrame: (CGRect)frame

{

CGFloat width = [self makeRandomNumberFromMin:15 toMax:self.originFrame.size.width];

CGRect randomFrame = CGRectMake(frame.origin.x, frame.origin.y, width , width);

return randomFrame;

}

//绘制贝塞尔曲线方法

//这里绘制贝塞尔曲线的方法需要重点讲一下:

大致原理图如下手稿所示



- (void)setUpBezierPath

{

//开始绘制泡泡的贝塞尔曲线

UIBezierPath *bezierPath = [UIBezierPath bezierPath];

[bezierPath moveToPoint:self.originPoint];

if (self.pathType == BubblePathTypeLeft) {

CGPoint leftControllPoint = CGPointMake(self.originPoint.x - self.nowMaxWidth / 2, self.originPoint.y - self.nowMaxHeight / 4);

CGPoint rightControllPoint = CGPointMake(self.originPoint.x + self.nowMaxWidth / 2, self.originPoint.y - self.nowMaxHeight *3 / 4);

CGPoint termalPoint = CGPointMake(self.originPoint.x, self.originPoint.y - self.nowMaxHeight);

[bezierPath addCurveToPoint:termalPoint controlPoint1:leftControllPoint controlPoint2:rightControllPoint];

}else{

CGPoint leftControllPoint = CGPointMake(self.originPoint.x - self.nowMaxWidth / 2, self.originPoint.y - self.nowMaxHeight * 3 / 4);

CGPoint rightControllPoint = CGPointMake(self.originPoint.x + self.nowMaxWidth / 2, self.originPoint.y - self.nowMaxHeight / 4);

CGPoint termalPoint = CGPointMake(self.originPoint.x, self.originPoint.y - self.nowMaxHeight);

[bezierPath addCurveToPoint:termalPoint controlPoint1:rightControllPoint controlPoint2:leftControllPoint];

}

// self.shapeLayer = [CAShapeLayer layer];

// self.shapeLayer .path = bezierPath.CGPath;

// [self.shapeLayer setStrokeColor:[UIColor redColor].CGColor];

// [self.superview.layer addSublayer:self.shapeLayer ];

CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];

[keyFrameAnimation setDuration:2.0];

keyFrameAnimation.path = bezierPath.CGPath;

keyFrameAnimation.fillMode = kCAFillModeForwards;

keyFrameAnimation.removedOnCompletion = NO;

keyFrameAnimation.delegate = self;

[self.layer addAnimation:keyFrameAnimation forKey:@"movingAnimation"];

}

//绘制完贝塞尔曲线和添加玩动画之后,我们在动画停止之后的那个方法进行爆破动画

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag

{

[CATransaction begin];

[CATransaction setCompletionBlock:^{

// transform the image to be 1.3 sizes larger to

// give the impression that it is popping

[UIView transitionWithView:self

duration:0.1f

options:UIViewAnimationOptionTransitionCrossDissolve

animations:^{

self.transform = CGAffineTransformMakeScale(1.3, 1.3);

} completion:^(BOOL finished) {

if (finished == YES) {

[self.layer removeAllAnimations];

BubbleImageView *bubbleImageView = [[BubbleImageView alloc]initWithMaxHeight:self.maxHeight maxWidth:self.maxWidth maxFrame:self.originFrame andSuperView:self.superview];

// [self.shapeLayer removeFromSuperlayer];

[self removeFromSuperview];

}

}];

}];

[CATransaction commit];

}

//完成一个泡泡的封装之后,你若将它直接添加到view上面去将会看到这样的效果



//接下来我们来将一下蓝色的渐变色是怎么制作的,需要用到一个CALayer的子类CAGradientLayer,只要将它的colors数组赋值,便能够实现渐变的效果,当然你也可以指定它的startPoint和endPoint默认是渐变方向从上往下,所以这里并没有指定

CAGradientLayer *gradientLayer = [[CAGradientLayer alloc]init];

[gradientLayer setFrame:CGRectMake(0, [UIScreen mainScreen].bounds.size.height / 2, self.view.bounds.size.width, self.view.bounds.size.height / 2)];

gradientLayer.colors = @[(__bridge id)[UIColor whiteColor].CGColor,(__bridge id)[UIColor colorWithRed:0 green:0.5 blue:1 alpha:0.5].CGColor,(__bridge id)[UIColor blueColor].CGColor];

[self.view.layer addSublayer:gradientLayer];

//好了,我们的泡泡动画到这里就结束了,代码的设计上并不是很难,关键在相关参数的调试上,如果你需要Demo的话可以到我的GitHub上面下载

//下载地址是:

  https://github.com/bnb173yjx/BubbleAnimationDemo

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: