版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.12.13 |
前言
如果你细看了我前面写的有关动画的部分,就知道前面介绍了
CoreAnimation
、序列帧以及LOTAnimation
等很多动画方式,接下来几篇我们就以动画示例为线索,进行动画的讲解。相关代码已经上传至GitHub - 刀客传奇。感兴趣的可以看我写的前面几篇。
1. 动画示例(一) —— 一种外扩的简单动画
2. 动画示例(二) —— 一种抖动的简单动画
3. 动画示例(三) —— 仿头条一种LOTAnimation动画
4. 动画示例(四) —— QuartzCore之CAEmitterLayer下雪❄️动画
5. 动画示例(五) —— QuartzCore之CAEmitterLayer烟花动画
功能要求
QuartzCore框架中CAEmitterLayer
、CAReplicatorLayer
和CAGradientLayer
是很重要的三个类,特别是在做动画的时候很给力,这里就简单的实现基于它们三个的简单动画,这个动画不是我原创,下面给出链接,致敬原作者。
GitHub - YUAnimation
功能实现
首先看一下CAReplicatorLayer
类的API
/* CoreAnimation - CAReplicatorLayer.h
Copyright (c) 2008-2017, Apple Inc.
All rights reserved. */
#import
NS_ASSUME_NONNULL_BEGIN
/* The replicator layer creates a specified number of copies of its
* sublayers, each copy potentially having geometric, temporal and
* color transformations applied to it.
*
* Note: the CALayer -hitTest: method currently only tests the first
* instance of z replicator layer's sublayers. This may change in the
* future. */
CA_CLASS_AVAILABLE (10.6, 3.0, 9.0, 2.0)
@interface CAReplicatorLayer : CALayer
/* The number of copies to create, including the source object.
* Default value is one (i.e. no extra copies). Animatable. */
@property NSInteger instanceCount;
/* Defines whether this layer flattens its sublayers into its plane or
* not (i.e. whether it's treated similarly to a transform layer or
* not). Defaults to NO. If YES, the standard restrictions apply (see
* CATransformLayer.h). */
@property BOOL preservesDepth;
/* The temporal delay between replicated copies. Defaults to zero.
* Animatable. */
@property CFTimeInterval instanceDelay;
/* The matrix applied to instance k-1 to produce instance k. The matrix
* is applied relative to the center of the replicator layer, i.e. the
* superlayer of each replicated sublayer. Defaults to the identity
* matrix. Animatable. */
@property CATransform3D instanceTransform;
/* The color to multiply the first object by (the source object). Defaults
* to opaque white. Animatable. */
@property(nullable) CGColorRef instanceColor;
/* The color components added to the color of instance k-1 to produce
* the modulation color of instance k. Defaults to the clear color (no
* change). Animatable. */
@property float instanceRedOffset;
@property float instanceGreenOffset;
@property float instanceBlueOffset;
@property float instanceAlphaOffset;
@end
NS_ASSUME_NONNULL_END
接着再看一下类CAGradientLayer
。
/* CoreAnimation - CAGradientLayer.h
Copyright (c) 2008-2017, Apple Inc.
All rights reserved. */
/* The gradient layer draws a color gradient over its background color,
* filling the shape of the layer (i.e. including rounded corners). */
#import
#import
NS_ASSUME_NONNULL_BEGIN
CA_CLASS_AVAILABLE (10.6, 3.0, 9.0, 2.0)
@interface CAGradientLayer : CALayer
/* The array of CGColorRef objects defining the color of each gradient
* stop. Defaults to nil. Animatable. */
@property(nullable, copy) NSArray *colors;
/* An optional array of NSNumber objects defining the location of each
* gradient stop as a value in the range [0,1]. The values must be
* monotonically increasing. If a nil array is given, the stops are
* assumed to spread uniformly across the [0,1] range. When rendered,
* the colors are mapped to the output colorspace before being
* interpolated. Defaults to nil. Animatable. */
@property(nullable, copy) NSArray *locations;
/* The start and end points of the gradient when drawn into the layer's
* coordinate space. The start point corresponds to the first gradient
* stop, the end point to the last gradient stop. Both points are
* defined in a unit coordinate space that is then mapped to the
* layer's bounds rectangle when drawn. (I.e. [0,0] is the bottom-left
* corner of the layer, [1,1] is the top-right corner.) The default values
* are [.5,0] and [.5,1] respectively. Both are animatable. */
@property CGPoint startPoint;
@property CGPoint endPoint;
/* The kind of gradient that will be drawn. Currently the only allowed
* value is `axial' (the default value). */
@property(copy) NSString *type;
@end
/** `type' values. **/
CA_EXTERN NSString * const kCAGradientLayerAxial
CA_AVAILABLE_STARTING (10.6, 3.0, 9.0, 2.0);
NS_ASSUME_NONNULL_END
下面我们就看一下代码
1. YUMainTableViewController.h
#import
@interface YUMainTableViewController : UITableViewController
@end
2. YUMainTableViewController.m
#import "YUMainTableViewController.h"
#import "YUAnimationViewController.h"
@interface YUMainTableViewController ()
{
// 各种layer动画
NSArray *_layerTypes;
}
@end
@implementation YUMainTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"三种特殊的layer动画";
_layerTypes = @[@"CAReplicatorLayer 复制层动画", @"CAEmitterLayer 粒子动画", @"CAGradientLayer 渐变动画"];
self.tableView.tableFooterView = [[UIView alloc] init];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _layerTypes.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = @"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.textLabel.text = _layerTypes[indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
YUAnimationViewController *animationCtrl = [[YUAnimationViewController alloc] init];
animationCtrl.layerType = indexPath.row;
animationCtrl.title = _layerTypes[indexPath.row];
[self.navigationController pushViewController:animationCtrl animated:YES];
}
@end
3. YUAnimationViewController.h
#import
#import "YUReplicatorAnimation.h"
// layer类型
typedef NS_ENUM(NSUInteger, YULayerType){
YUCAReplicatorLayer, // 复制动画
YUCAEmitterLayer, // 粒子动画
YUCAGradientLayer, // 渐变动画
};
@interface YUAnimationViewController : UITableViewController
@property (nonatomic, assign) YULayerType layerType;
@property (nonatomic, assign) YUReplicatorLayerType replicatorLayerType;
@end
4. YUAnimationViewController.m
#import "YUAnimationViewController.h"
#import "YULoadingLabel.h"
#import "SnowView.h"
@interface YUAnimationViewController ()
{
// 各种CAReplicatorLayer的动画
NSArray *_animationTypes;
}
@property (nonatomic, strong) SnowView *snow;
@end
@implementation YUAnimationViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.tableFooterView = [[UIView alloc] init];
}
// 三种layer的动画
- (void)setLayerType:(YULayerType)layerType
{
switch (layerType) {
case YUCAReplicatorLayer:
{
[self setupCAReplicatorLayerAnimation];
}
break;
case YUCAEmitterLayer:
{
[self setupCAEmitterLayer];
self.view.backgroundColor = [UIColor grayColor];
}
break;
case YUCAGradientLayer:
{
[self setupCAGradientLayer];
self.view.backgroundColor = [UIColor grayColor];
}
break;
default:
break;
}
}
#pragma mark ----------------------- 各种CAReplicatorLayer的动画
- (void)setReplicatorLayerType:(YUReplicatorLayerType)replicatorLayerType
{
CGFloat width = 100;
CGRect viewframe = CGRectMake((kScreenWidth - width) / 2, 150, width, width);
switch (replicatorLayerType) {
case YUReplicatorLayerShake:
viewframe = CGRectMake(80, 200, width, width);
break;
case YUReplicatorLayerHeart:
viewframe = CGRectMake(0, 64, width, width);
break;
default:
break;
}
UIView *aniView = [[UIView alloc] initWithFrame:viewframe];
[self.view addSubview:aniView];
[aniView.layer addSublayer: [YUReplicatorAnimation replicatorLayerWithType:replicatorLayerType]];
self.view.backgroundColor = [UIColor grayColor];
}
- (void)setupCAReplicatorLayerAnimation
{
_animationTypes = @[@"波纹 animation", @"波浪 animation", @"三角形 animation", @"网格 animation", @"条形 animation", @"转圈 animation", @"心 animation", @"翻转 animation"];
}
#pragma mark ----------------------- CAEmitterLayer 粒子动画
- (void)setupCAEmitterLayer
{
self.snow = [[SnowView alloc] initWithFrame:CGRectMake(100, 100, kScreenWidth / 2.f, kScreenWidth / 2.f)];
// self.snow.backgroundColor = [UIColor grayColor];
[self.view addSubview:self.snow];
self.snow.snowImage = [UIImage imageNamed:@"snow"];
self.snow.birthRate = 20.f;
self.snow.gravity = 5.f;
self.snow.snowColor = [UIColor whiteColor];
CALayer *layer = [CALayer layer];
layer.anchorPoint = CGPointMake(0, 0); // 重置锚点
layer.bounds = CGRectMake(0, 0, kScreenWidth / 2.f, kScreenWidth / 2.f); // 设置尺寸
UIImage *image = [UIImage imageNamed:@"alpha"];
if (image) {
layer.contents = (__bridge id)(image.CGImage);
}
self.snow.layer.mask = layer;
[self.snow showSnow];
}
#pragma mark ----------------------- 渐变动画
- (void)setupCAGradientLayer
{
// CAGradientLayer 动画
YULoadingLabel *loadingLabel = [YULoadingLabel loadingLabel];
loadingLabel.frame = CGRectMake(100, 100, 200, 100);
[loadingLabel showLoadingInView:self.view text:nil];
YULoadingLabel *loadingLabel2 = [YULoadingLabel loadingLabel];
loadingLabel.textColor = [UIColor redColor];
loadingLabel2.frame = CGRectMake(110, 200, 200, 100);
[loadingLabel2 showLoadingInView:self.view text:@"加载动画"];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _animationTypes.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = @"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.textLabel.text = _animationTypes[indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
YUAnimationViewController *animationCtrl = [[YUAnimationViewController alloc] init];
animationCtrl.replicatorLayerType = indexPath.row;
animationCtrl.title = _animationTypes[indexPath.row];
[self.navigationController pushViewController:animationCtrl animated:YES];
}
@end
5. YUReplicatorAnimation.h
#import
// 动画类型
typedef NS_ENUM(NSUInteger, YUReplicatorLayerType){
YUReplicatorLayerCircle,
YUReplicatorLayerWave,
YUReplicatorLayerTriangle,
YUReplicatorLayerGrid,
YUReplicatorLayerShake,
YUReplicatorLayerRound,
YUReplicatorLayerHeart,
YUReplicatorLayerTurn,
};
@interface YUReplicatorAnimation : NSObject
+ (CALayer *)replicatorLayerWithType:(YUReplicatorLayerType)type;
// 波纹
+ (CALayer *)replicatorLayer_Circle;
// 波浪
+ (CALayer *)replicatorLayer_Wave;
// 三角形
+ (CALayer *)replicatorLayer_Triangle;
// 网格
+ (CALayer *)replicatorLayer_Grid;
// 震东条
+ (CALayer *)replicatorLayer_Shake;
// 转圈动画
+ (CALayer *)replicatorLayer_Round;
// 心动画
+ (CALayer *)replicatorLayer_Heart;
@end
6. YUReplicatorAnimation.m
#import "YUReplicatorAnimation.h"
@implementation YUReplicatorAnimation
+ (CALayer *)replicatorLayerWithType:(YUReplicatorLayerType)type
{
CALayer *layer = nil;
switch (type) {
case YUReplicatorLayerCircle:
{
layer = [self replicatorLayer_Circle];
}
break;
case YUReplicatorLayerWave:
{
layer = [self replicatorLayer_Wave];
}
break;
case YUReplicatorLayerTriangle:
{
layer = [self replicatorLayer_Triangle];
}
break;
case YUReplicatorLayerGrid:
{
layer = [self replicatorLayer_Grid];
}
break;
case YUReplicatorLayerShake:
{
layer = [self replicatorLayer_Shake];
}
break;
case YUReplicatorLayerRound:
{
layer = [self replicatorLayer_Round];
}
break;
case YUReplicatorLayerHeart:
{
layer = [self replicatorLayer_Heart];
}
break;
case YUReplicatorLayerTurn:
{
layer = [self replicatorLayer_Turn];
}
break;
default:
{
layer = [self replicatorLayer_Circle];
}
break;
}
return layer;
}
#pragma mark ----------------------- 复制层
// 圆圈动画 波纹
+ (CALayer *)replicatorLayer_Circle{
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = CGRectMake(0, 0, 80, 80);
shapeLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 80, 80)].CGPath;
shapeLayer.fillColor = [UIColor redColor].CGColor;
shapeLayer.opacity = 0.0;
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = @[[self alphaAnimation],[self scaleAnimation]];
animationGroup.duration = 4.0;
animationGroup.autoreverses = NO;
animationGroup.repeatCount = HUGE;
[shapeLayer addAnimation:animationGroup forKey:@"animationGroup"];
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
replicatorLayer.frame = CGRectMake(0, 0, 80, 80);
replicatorLayer.instanceDelay = 0.5;
replicatorLayer.instanceCount = 8;
[replicatorLayer addSublayer:shapeLayer];
return replicatorLayer;
}
// 波动动画
+ (CALayer *)replicatorLayer_Wave{
CGFloat between = 5.0;
CGFloat radius = (100-2*between)/3;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = CGRectMake(0, (100-radius)/2, radius, radius);
shapeLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, radius, radius)].CGPath;
shapeLayer.fillColor = [UIColor redColor].CGColor;
[shapeLayer addAnimation:[self scaleAnimation1] forKey:@"scaleAnimation"];
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
replicatorLayer.frame = CGRectMake(0, 0, 100, 100);
replicatorLayer.instanceDelay = 0.2;
replicatorLayer.instanceCount = 3;
replicatorLayer.instanceTransform = CATransform3DMakeTranslation(between*2+radius,0,0);
[replicatorLayer addSublayer:shapeLayer];
return replicatorLayer;
}
// 三角形动画
+ (CALayer *)replicatorLayer_Triangle{
CGFloat radius = 100/4;
CGFloat transX = 100 - radius;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = CGRectMake(0, 0, radius, radius);
shapeLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, radius, radius)].CGPath;
shapeLayer.strokeColor = [UIColor redColor].CGColor;
shapeLayer.fillColor = [UIColor redColor].CGColor;
shapeLayer.lineWidth = 1;
[shapeLayer addAnimation:[self rotationAnimation:transX] forKey:@"rotateAnimation"];
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
replicatorLayer.frame = CGRectMake(0, 0, radius, radius);
replicatorLayer.instanceDelay = 0.0;
replicatorLayer.instanceCount = 3;
CATransform3D trans3D = CATransform3DIdentity;
trans3D = CATransform3DTranslate(trans3D, transX, 0, 0);
trans3D = CATransform3DRotate(trans3D, 120.0*M_PI/180.0, 0.0, 0.0, 1.0);
replicatorLayer.instanceTransform = trans3D;
[replicatorLayer addSublayer:shapeLayer];
return replicatorLayer;
}
// 网格动画
+ (CALayer *)replicatorLayer_Grid{
NSInteger column = 3;
CGFloat between = 5.0;
CGFloat radius = (100 - between * (column - 1))/column;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = CGRectMake(0, 0, radius, radius);
shapeLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, radius, radius)].CGPath;
shapeLayer.fillColor = [UIColor redColor].CGColor;
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = @[[self scaleAnimation1], [self alphaAnimation]];
animationGroup.duration = 1.0;
animationGroup.autoreverses = YES;
animationGroup.repeatCount = HUGE;
[shapeLayer addAnimation:animationGroup forKey:@"groupAnimation"];
CAReplicatorLayer *replicatorLayerX = [CAReplicatorLayer layer];
replicatorLayerX.frame = CGRectMake(0, 0, 100, 100);
replicatorLayerX.instanceDelay = 0.3;
replicatorLayerX.instanceCount = column;
replicatorLayerX.instanceTransform = CATransform3DTranslate(CATransform3DIdentity, radius+between, 0, 0);
[replicatorLayerX addSublayer:shapeLayer];
CAReplicatorLayer *replicatorLayerY = [CAReplicatorLayer layer];
replicatorLayerY.frame = CGRectMake(0, 0, 100, 100);
replicatorLayerY.instanceDelay = 0.3;
replicatorLayerY.instanceCount = column;
replicatorLayerY.instanceTransform = CATransform3DTranslate(CATransform3DIdentity, 0, radius+between, 0);
[replicatorLayerY addSublayer:replicatorLayerX];
return replicatorLayerY;
}
// 震动条动画
+ (CALayer *)replicatorLayer_Shake{
CALayer *layer = [[CALayer alloc]init];
layer.frame = CGRectMake(0, 0, 10, 80);
layer.backgroundColor = [UIColor redColor].CGColor;
layer.anchorPoint = CGPointMake(0.5, 1);
// 添加一个基本动画
[layer addAnimation:[self scaleYAnimation] forKey:@"scaleAnimation"];
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
replicatorLayer.frame = CGRectMake(0, 0, 80, 80);
replicatorLayer.instanceCount = 6;
replicatorLayer.instanceTransform = CATransform3DMakeTranslation(45, 0, 0);
replicatorLayer.instanceDelay = 0.2;
replicatorLayer.instanceGreenOffset = -0.3;
[replicatorLayer addSublayer:layer];
return replicatorLayer;
}
// 转圈动画
+ (CALayer *)replicatorLayer_Round{
CALayer *layer = [[CALayer alloc]init];
layer.frame = CGRectMake(0, 0, 12, 12);
layer.cornerRadius = 6;
layer.masksToBounds = YES;
layer.transform = CATransform3DMakeScale(0.01, 0.01, 0.01);
layer.backgroundColor = [UIColor purpleColor].CGColor;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.duration = 1;
animation.repeatCount = MAXFLOAT;
animation.fromValue = @(1);
animation.toValue = @(0.01);
[layer addAnimation:animation forKey:nil];
NSInteger instanceCount = 9;
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
replicatorLayer.frame = CGRectMake(0, 0, 50, 50);
replicatorLayer.preservesDepth = YES;
replicatorLayer.instanceColor = [UIColor whiteColor].CGColor;
replicatorLayer.instanceRedOffset = 0.1;
replicatorLayer.instanceGreenOffset = 0.1;
replicatorLayer.instanceBlueOffset = 0.1;
replicatorLayer.instanceAlphaOffset = 0.1;
replicatorLayer.instanceCount = instanceCount;
replicatorLayer.instanceDelay = 1.0/instanceCount;
replicatorLayer.instanceTransform = CATransform3DMakeRotation((2 * M_PI) /instanceCount, 0, 0, 1);
[replicatorLayer addSublayer:layer];
return replicatorLayer;
}
// 心动画
+ (CALayer *)replicatorLayer_Heart{
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer new];
replicatorLayer.frame = CGRectMake(0, 0, 200, 200);
// replicatorLayer.backgroundColor = [UIColor colorWithWhite:0 alpha:0.75].CGColor;
CALayer *subLayer = [CALayer new];
subLayer.bounds = CGRectMake(60, 105, 10, 10);
subLayer.backgroundColor = [UIColor colorWithWhite:0.8 alpha:1.0].CGColor;
subLayer.borderColor = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;
subLayer.borderWidth = 1.0;
subLayer.cornerRadius = 5.0;
subLayer.shouldRasterize = YES;
subLayer.rasterizationScale = [UIScreen mainScreen].scale;
[replicatorLayer addSublayer:subLayer];
CAKeyframeAnimation *move = [CAKeyframeAnimation animationWithKeyPath:@"position"];
move.path = [self heartPath];
move.repeatCount = INFINITY;
move.duration = 6.0;
// move.autoreverses = YES;
[subLayer addAnimation:move forKey:nil];
replicatorLayer.instanceDelay = 6/50.0;
replicatorLayer.instanceCount = 50;
replicatorLayer.instanceColor = [UIColor orangeColor].CGColor;
replicatorLayer.instanceGreenOffset = -0.03;
return replicatorLayer;
}
// 翻转动画
+ (CALayer *)replicatorLayer_Turn
{
CGFloat margin = 8.0;
CGFloat width = 80;
CGFloat dotW = (width - 2 * margin) / 3;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = CGRectMake(0, (width - dotW) * 0.5, dotW, dotW);
shapeLayer.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, dotW, dotW)].CGPath;
shapeLayer.fillColor = [UIColor redColor].CGColor;
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
replicatorLayer.frame = CGRectMake(0, 0, width, width);
replicatorLayer.instanceDelay = 0.1;
replicatorLayer.instanceCount = 3;
CATransform3D transform = CATransform3DMakeTranslation(margin + dotW, 0, 0);
replicatorLayer.instanceTransform = transform;
[replicatorLayer addSublayer:shapeLayer];
CABasicAnimation *basicAnima = [CABasicAnimation animationWithKeyPath:@"transform"];
basicAnima.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, 0, 0, 1.0, 0)];
basicAnima.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, M_PI, 0, 1.0, 0)];
basicAnima.repeatCount = HUGE;
basicAnima.duration = 0.6;
[shapeLayer addAnimation:basicAnima forKey:nil];
return replicatorLayer;
}
#pragma mark ----------------------- 基础动画
+ (CGPathRef)heartPath
{
CGFloat W = 25;
CGFloat marginX = 10;
CGFloat marginY = 15/25.0 * W;
CGFloat space = 5/25.0 * W;
UIBezierPath *bezierPath = [UIBezierPath new];
[bezierPath moveToPoint:(CGPointMake(marginX + W * 2, W * 4 + space))];
[bezierPath addQuadCurveToPoint:CGPointMake(marginX, W * 2) controlPoint:CGPointMake(W, W * 4 - space)];
[bezierPath addCurveToPoint:CGPointMake(marginX + W * 2, W * 2) controlPoint1:CGPointMake(marginX, marginY) controlPoint2:CGPointMake(marginX + W * 2, marginY)];
[bezierPath addCurveToPoint:CGPointMake(marginX + W * 4, W * 2) controlPoint1:CGPointMake(marginX + W * 2, marginY) controlPoint2:CGPointMake(marginX + W * 4, marginY)];
[bezierPath addQuadCurveToPoint:CGPointMake(marginX + W * 2, W * 4 + space) controlPoint:CGPointMake(marginX * 2 + W * 3, W * 4 - space)];
[bezierPath closePath];
CGAffineTransform T = CGAffineTransformMakeScale(3.0, 3.0);
return CGPathCreateCopyByTransformingPath(bezierPath.CGPath, &T);
}
+ (CABasicAnimation *)scaleYAnimation{
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"];
anim.toValue = @0.1;
anim.duration = 0.4;
anim.autoreverses = YES;//往返都有动画
anim.repeatCount = MAXFLOAT;//执行次数
return anim;
}
+ (CABasicAnimation *)alphaAnimation{
CABasicAnimation *alpha = [CABasicAnimation animationWithKeyPath:@"opacity"];
alpha.fromValue = @(1.0);
alpha.toValue = @(0.0);
return alpha;
}
+ (CABasicAnimation *)scaleAnimation{
CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:@"transform"];
scale.fromValue = [NSValue valueWithCATransform3D:CATransform3DScale(CATransform3DIdentity, 0.0, 0.0, 0.0)];
scale.toValue = [NSValue valueWithCATransform3D:CATransform3DScale(CATransform3DIdentity, 1.0, 1.0, 0.0)];
return scale;
}
+ (CABasicAnimation *)scaleAnimation1{
CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:@"transform"];
scale.fromValue = [NSValue valueWithCATransform3D:CATransform3DScale(CATransform3DIdentity, 1.0, 1.0, 0.0)];
scale.toValue = [NSValue valueWithCATransform3D:CATransform3DScale(CATransform3DIdentity, 0.2, 0.2, 0.0)];
scale.autoreverses = YES;
scale.repeatCount = HUGE;
scale.duration = 0.6;
return scale;
}
+ (CABasicAnimation *)rotationAnimation:(CGFloat)transX{
CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:@"transform"];
CATransform3D fromValue = CATransform3DRotate(CATransform3DIdentity, 0.0, 0.0, 0.0, 0.0);
scale.fromValue = [NSValue valueWithCATransform3D:fromValue];
CATransform3D toValue = CATransform3DTranslate(CATransform3DIdentity, transX, 0.0, 0.0);
toValue = CATransform3DRotate(toValue,120.0*M_PI/180.0, 0.0, 0.0, 1.0);
scale.toValue = [NSValue valueWithCATransform3D:toValue];
scale.autoreverses = NO;
scale.repeatCount = HUGE;
scale.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
scale.duration = 0.8;
return scale;
}
@end
7. YULoadingLabel.h
#import
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
@interface YULoadingLabel : UILabel
// 创建Label
+ (YULoadingLabel *)loadingLabel;
// 显示加载动画
- (void)showLoadingInView:(UIView *)view text:(NSString *)text;
// 隐藏
- (void)hide;
@end
8. YULoadingLabel.m
#import "YULoadingLabel.h"
@implementation YULoadingLabel
+ (YULoadingLabel *)loadingLabel
{
return [[self alloc] init];
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.textColor = [UIColor blueColor];
self.font = [UIFont systemFontOfSize:35];
self.text = @"timelyRain";
}
return self;
}
- (void)showLoadingInView:(UIView *)view text:(NSString *)text
{
[view addSubview:self];
if (text) {
self.text = text;
}
[self sizeToFit];
// 创建渐变效果的layer
CAGradientLayer *graLayer = [CAGradientLayer layer];
graLayer.frame = self.bounds;
graLayer.colors = @[(__bridge id)[[UIColor greenColor] colorWithAlphaComponent:0.3].CGColor,
(__bridge id)[UIColor yellowColor].CGColor,
(__bridge id)[[UIColor yellowColor] colorWithAlphaComponent:0.3].CGColor];
graLayer.startPoint = CGPointMake(0, 0.1);//设置渐变方向起点
graLayer.endPoint = CGPointMake(1, 0); //设置渐变方向终点
graLayer.locations = @[@(0.0), @(0.0), @(0.1)]; //colors中各颜色对应的初始渐变点
// 创建动画
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"locations"];
animation.duration = 1.0f;
animation.toValue = @[@(0.9), @(1.0), @(1.0)];
animation.removedOnCompletion = NO;
animation.repeatCount = HUGE_VALF;
animation.fillMode = kCAFillModeForwards;
[graLayer addAnimation:animation forKey:@"xindong"];
// 将graLayer设置成textLabel的遮罩
self.layer.mask = graLayer;
}
- (void)hide
{
[self removeFromSuperview];
}
@end
9. EmitterLayerView.h
#import
typedef enum : NSUInteger {
__SNOW = 0x11,
__RAIN,
__NONE,
} EMitterType;
@interface EmitterLayerView : UIView
/**
* 重写setter,getter方法,可以在程序中直接使用点语法
*/
- (void)setEmitterLayer:(CAEmitterLayer *)layer;
- (CAEmitterLayer *)emitterLayer;
- (void)show;
- (void)hide;
- (void)configType:(EMitterType)type;
@end
10.EmitterLayerView.m
#import "EmitterLayerView.h"
@interface EmitterLayerView () {
CAEmitterLayer *_layer;
}
@end
@implementation EmitterLayerView
/**
* 替换layer
*
* @return 替换当前view的layer
*/
+ (Class)layerClass {
return [CAEmitterLayer class];
}
/**
* 模拟setter,getter方法
*
*/
- (void)setEmitterLayer:(CAEmitterLayer *)layer {
_layer = layer;
}
- (CAEmitterLayer *)emitterLayer {
return _layer;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_layer = (CAEmitterLayer *)self.layer;
}
return self;
}
- (void)show {
}
- (void)hide {
}
- (void)configType:(EMitterType)type {
}
@end
11. SnowView.h
#import "EmitterLayerView.h"
@interface SnowView : EmitterLayerView
@property (nonatomic, strong) UIImage *snowImage;
@property (nonatomic, assign) CGFloat lifetime; // 生命周期
@property (nonatomic, assign) CGFloat birthRate; // 出生率
@property (nonatomic, assign) CGFloat speed; // 雪花速率
@property (nonatomic, assign) CGFloat speedRange; // 速率变化范围 [speed - speedRange , speed + speedRange]
@property (nonatomic, assign) CGFloat gravity; // 重力
@property (nonatomic, strong) UIColor *snowColor; // 雪花颜色
- (void)showSnow;
- (void)show;
- (void)hide;
- (void)configType:(EMitterType)type;
@end
12.SnowView.m
#import "SnowView.h"
@implementation SnowView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
self.emitterLayer.emitterShape = kCAEmitterLayerLine; // 直线粒子发射器
self.emitterLayer.emitterMode = kCAEmitterLayerSurface; // ?????
self.emitterLayer.emitterSize = self.frame.size; // 发射区域
self.emitterLayer.emitterPosition = CGPointMake(self.bounds.size.width / 2.f, - 5); // 发射中心点位置
}
- (void)showSnow {
if (_snowImage == nil) {
return;
}
// 创建雪花类型的粒子
CAEmitterCell *snowflake = [CAEmitterCell emitterCell];
// 粒子的名字
snowflake.name = @"snow";
// 粒子参数的速度乘数因子
snowflake.birthRate = (_birthRate > 0 ? _birthRate : 1.f);
// 粒子生命周期
snowflake.lifetime = (_lifetime > 0 ? _lifetime : 60);
// 粒子速度
snowflake.velocity = (_speed > 0 ? _speed : 10.f);
// 粒子的速度范围
snowflake.velocityRange = (_speedRange > 0 ? _speedRange : 10.f);
// 粒子y方向的加速度分量(可以理解为重力)
snowflake.yAcceleration = (_gravity != 0 ? _gravity : 2.f);
// 每个发射的粒子的初始时候随机的角度
snowflake.emissionRange = 0.5 * M_PI;
// 粒子旋转角度
snowflake.spinRange = 0.25 * M_PI;
// 获取图片
snowflake.contents = (id)_snowImage.CGImage;
// 设置雪花形状的粒子的颜色
snowflake.color = (_snowColor == nil ? [[UIColor whiteColor] CGColor] :_snowColor.CGColor);
// 尺寸
snowflake.scale = 0.5f;
// 尺寸变化范围
snowflake.scaleRange = 0.3f;
// 添加粒子
self.emitterLayer.emitterCells = @[snowflake];
}
- (void)configType:(EMitterType)type {
if (type == __SNOW) {
// 配置
self.birthRate = 5.f;
self.snowImage = [UIImage imageNamed:@"snow"];
self.snowColor = [UIColor blackColor];
self.lifetime = 30.f;
self.alpha = 0.f;
UIImageView *snowAlpha = [[UIImageView alloc] initWithFrame:self.bounds];
snowAlpha.image = [UIImage imageNamed:@"alpha"];
self.maskView = snowAlpha;
}
}
- (void)show {
[self showSnow];
[UIView animateWithDuration:1.75f animations:^{
self.alpha = 0.5f;
}];
}
- (void)hide {
[UIView animateWithDuration:0.75 animations:^{
self.alpha = 0.f;
} completion:^(BOOL finished) {
}];
}
@end
功能效果
下面我们就看结果效果图。
后记
未完,待续~~~