神奇的CAReplicatorLayer

文档描述:

The CAReplicatorLayer class creates a specified number of copies of its sublayers (the source layer), each copy potentially having geometric, temporal and color transformations applied to it.

简介

  • 支持系统:>=iOS3.0。
  • 文档释义:CAReplicatorLayer类可用来从layer源高效复制多个实体对象,每个实体对象都可以拥有几何形状、颜色、时间层次上的不同转换。
  • 实际应用: 加载动画、镜像layer的生成。

使用示例1:实现一个镜像反射效果

1.创建一个模板层

  /*        创建一个模板层 CAReplicatorLayer会按照一定的规则“克隆”这个模板         */
  CAShapeLayer *shape = [CAShapeLayer layer];
  shape.frame = CGRectMake(0, 0, 80, 80);
  /*        绘制模板的形状         */
  shape.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 80, 80)].CGPath;
  /*        模板的填充颜色         */
  shape.fillColor = [UIColor redColor].CGColor;
  shape.opacity = 0.0;
  /*        创建所有的子层的动画组(也可以是单个动画)         */
  CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
  /*        动画组元素         */
  animationGroup.animations = @[[self alphaAnimation],[self scaleAnimation]];
  /*        动画执行时间         */
  animationGroup.duration = 4.0;
  animationGroup.autoreverses = NO;
  animationGroup.repeatCount = HUGE;
  /*        给模板层添加动画 实质上也是给每个CAReplicatorLayer子层添加动画         */
  [shape addAnimation:animationGroup forKey:@"animationGroup"];
  /*        创建CAReplicatorLayer对象         */
  CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
  replicatorLayer.frame = self.containerView.bounds;
  /*        设置每个元素的添加间隔时间         */
  replicatorLayer.instanceDelay = 0.5;
  /*        设置每元素个数         */
  replicatorLayer.instanceCount = 8;
  /*        给CAReplicatorLayer对象的子层添加转换规则 这里决定了子层的布局         */
  replicatorLayerY.instanceTransform = CATransform3DTranslate(CATransform3DIdentity, 0, radius+between, 0);
  /*        添加子层         */
  [replicatorLayer addSublayer:shape];

Note:在这里,大家可以根据需要添加不同的动画元素或者不添加任何动画,该用法多用于实现加载提示视图的动画制作。

2.实现某个视图的反射效果

我们首先继承UIView创建一个子类,在子类的+(Class)layerClass方法中设置当前视图对象的layer为CAReplicatorLayer对象:

  + (Class)layerClass{
   return [CAReplicatorLayer class];
  }

然后在创建该子类的对象时对self.layer进行设置相关参数:

- (void)setup{
/*        获取当前的layer 实际上为CAReplicatorLayer对象         */
CAReplicatorLayer *layer = (CAReplicatorLayer *)self.layer;
layer.instanceCount = 2;
layer.anchorPoint = CGPointMake(0.5, 0.5);

/*        创建3D转换效果         */
CATransform3D transform = CATransform3DIdentity;
CGFloat verticaloffset = self.bounds.size.height  ;
transform = CATransform3DTranslate(transform, 0, verticaloffset, 0);

/*        设置Y轴镜面反射         */
transform = CATransform3DScale(transform, 1, -1, 0);
transform = CATransform3DRotate(transform, -M_PI / 4, 1, 0, 0);
layer.instanceTransform  = transform;
/*        镜面的透明度 越低显示越清晰 因为是镜面效果         */
layer.instanceAlphaOffset = -0.1;
}

效果图如下:


镜像层.png

示例2:CAReplicatorLayer作为核心技术实现加载动画。

1.首先,创建一个UIView的子类,并暴露相关方法:

@interface JHHJView : UIView
/*        显示加载动画 并添加到父视图上         */
+ (void)showLoadingOnView:(UIView *)superView Type:(JHHJViewType)type;
/*        显示动画 并添加在主窗口上         */
+ (void)showLoadingOnTheKeyWindowWithType:(JHHJViewType)type;
/*        停止动画         */
+ (void)hideLoading;
/*        设置动画背景色(全屏背景色)         */
+ (void)backgroudColor:(UIColor *)color;
/*        设置中心视图的动画背景颜色 默认透明色         */
+ (void)centerBGViewBackgroudColor:(UIColor *)color;

2.并且声明了一个枚举类型:该枚举类型代表着加载动画类型。

typedef  NS_ENUM(NSInteger,JHHJViewType){
/**
 *  线性动画
 */
JHHJViewTypeSingleLine = 0,

/**
 *  方形点动画
 */
JHHJViewTypeSquare = 1,

/**
 *  三角形运动动画
 */
JHHJViewTypeTriangleTranslate = 2,

/**
 *  原型视图裁剪动画
 */
JHHJViewTypeClip
};

3.在.m文件中,该类拥有的成员变量如下:

@interface JHHJView ()
//中心背景视图
@property (nonatomic,strong)JHHJCenterBGView *centerBGView;
//计时器
@property (nonatomic,strong)NSTimer * clipTimer;
//层数组
@property (nonatomic,strong)NSMutableArray * clipLayerArr;
//计时器计量数
@property (nonatomic,assign) long long currentTimerIndex;
//背景层
@property (nonatomic,strong) CAShapeLayer *bgLayer;
@end

4.然后,设置以单例的方式创建该类的对象:

/**
 *  对象单例化
*
 *  @return 单例对象
*/
+ (JHHJView *)shareInstanceJHHJView{
static JHHJView * instance = nil;
if (!instance) {
    instance                     = [[JHHJView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    instance.centerBGView        = [[JHHJCenterBGView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    instance.centerBGView.center = CGPointMake(K_IOS_WIDTH / 2, K_IOS_HEIGHT/2);
    [instance addSubview:instance.centerBGView];
}
return instance;
}

5.动画的实现如下:

/**
 *  展示动画视图 并添加到依赖视图上
 *
*  @param superView 依赖的父视图
*  @param type      动画样式
*/
+ (void)showLoadingOnView:(UIView *)superView Type:(JHHJViewType)type{
/*        在显示前  先从父视图移除当前动画视图         */
JHHJView *instance = [[self class] shareInstanceJHHJView];
[[self class] hideLoading];
/*        显示前 先将动画图层从中心视图上移除         */
for (CALayer *layer in instance.centerBGView.layer.sublayers) {
    [layer removeFromSuperlayer];
}
/*        按照type初始化动画         */
switch (type) {
    case JHHJViewTypeSingleLine:
    {
        CALayer *layer = [instance lineAnimation];
        layer.position = CGPointMake(CGRectGetWidth(instance.centerBGView.frame)/2 - 25, CGRectGetHeight(instance.centerBGView.frame)/2);
        [instance.centerBGView.layer addSublayer:layer];
    }break;
        
    case JHHJViewTypeSquare:
    {
        CALayer *layer = [[self class] qurareAnimation];
        layer.position = CGPointMake(CGRectGetWidth(instance.centerBGView.frame)/2, CGRectGetHeight(instance.centerBGView.frame)/2);
        [instance.centerBGView.layer addSublayer:layer];
    }break;
    case JHHJViewTypeTriangleTranslate:
    {
        CALayer *layer = [[self class] triangleAnimation];
        layer.position = CGPointMake(CGRectGetWidth(instance.centerBGView.frame)/2 - 18, CGRectGetHeight(instance.centerBGView.frame)/2 - 15);
        [instance.centerBGView.layer addSublayer:layer];
    }break;
    case JHHJViewTypeClip:
    {
        
        CALayer *layer = [[self class] clipAnimation];
        layer.position = CGPointMake(CGRectGetWidth(instance.centerBGView.frame)/2 , CGRectGetHeight(instance.centerBGView.frame)/2 - 15);
        [instance.centerBGView.layer addSublayer:layer];
        
    }break;
    default:
        break;
}
[superView addSubview:instance];
}

6.下面来具体实现其中一个动画,以三角形旋转动画为例:

/**
*  三角形运动动画
 *
*  @return 动画实例对象
 */
+ (CALayer *)triangleAnimation{
/*        基本间距确定及模板层的创建         */
CGFloat radius                     = 50/4.0;
CGFloat transX                     = 50 - radius;
CAShapeLayer *shape                = [CAShapeLayer layer];
shape.frame                        = CGRectMake(0, 0, radius, radius);
shape.path                         = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, radius, radius)].CGPath;
shape.strokeColor                  = [UIColor redColor].CGColor;
shape.fillColor                    = [UIColor redColor].CGColor;
shape.lineWidth                    = 1;
[shape addAnimation:[JHHJAnimation rotateAnimation] 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:shape];
return replicatorLayer;
}

流程如上,效果图如下:

loading......

想要了解更多,源码在这里哦......

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,789评论 25 707
  • 水满杯中酒, 悲喜倒一壶。 觥筹有人梦, 此醉无人醒。
    月光徐风阅读 107评论 0 0
  • 记录一下(刚开始适配iOS11的时候用到的,出处都不记得。。。) 1.podfile iOS11添加下面的内容到P...
    宝宝丶菲阅读 452评论 0 0
  • 西湖边 没走出去也不会看到,有天研说:我买了新车,走,我带你去西湖兜风,我说好,我们去杨公堤,我喜欢那的陡坡,一阵...
    君君之阅读 147评论 0 0