iOS之UI--辉光动画

前言:学习来自YouXianMing老师的博客:《辉光UIView的category 》以及YouXianMing老师的github源码:《 GlowView

     而我个人考虑到分类的二次拓展性(或者是再一次拓展)不是特别好,所以将YouXianMing老师的用分类拓展的辉光动画,改写成一个继承CALayer的可拓展的普通类。

   一方面,也是作为自我训练编码,对辉光UIView的实现所使用到的上下文绘制、核心动画、GCD中的定时器以及Runtime动态添加属性等知识进一步的熟练运用和提高。

     个人经验不足,也许观点片面,读者尽量指出,我不会介意的。嘻嘻。

先展示效果图:

源码下载地址:https://github.com/HeYang123456789/UIView

源码:

 1 //
 2 //  GlowLayer.h
 3 //  GlowView
 4 //
 5 //  Created by HEYANG on 16/1/30.
 6 //  Copyright © 2016年 HeYang. All rights reserved.
 7 //
 8 
 9 #import <UIKit/UIKit.h>
10 
11 //                                     == 动画时间解析 ==
12 //
13 //  0.0 ----------- 0.0 ------------> glowOpacity [---------------] glowOpacity ------------> 0.0
14 //           T                T                           T                           T
15 //           |                |                           |                           |
16 //           |                |                           |                           |
17 //           .                .                           .                           .
18 //     hideDuration   animationDuration              glowDuration              animationDuration
19 //
20 
21 /**
22  *  需要考虑的参数
23  *  
24  *  需要考虑的逻辑
25  *      1.数值越界问题,通过懒加载
26  *      2.动画时间的安排(看前面的动画时间的解析)
27  *
28  *  需要对外公开的接口
29  */
30 
31 
32 @interface GlowLayer : CALayer
33 
34 #pragma mark - 对外公开的属性
35 
36 #pragma mark 设置辉光效果
37 /** 辉光的阴影半径 */
38 @property (nonatomic,strong)NSNumber *glowRadius;
39 /** 辉光的透明度 */
40 @property (nonatomic,strong)NSNumber *glowOpacity;
41 
42 #pragma mark 设置辉光的时间
43 /** 保持辉光的时间,默认设置为0.5f */
44 @property (nonatomic,strong)NSNumber *glowDuration;
45 /** 不显示辉光的时间,默认设置为0.5f */
46 @property (nonatomic,strong)NSNumber *hideDuration;
47 /** 辉光的变化时间,从明到暗或者是从暗到明,默认设置为1.f */
48 @property (nonatomic,strong)NSNumber *glowAnimationDuration;
49 
50 
51 #pragma mark - 对外公开的接口
52 
53 /** 在原始的View上创建出辉光layer */
54 -(void)createGlowLayerWithOriginView:(UIView*)originView glowColor:(UIColor*)glowColor;
55 
56 /** 显示辉光 */
57 -(void)showGLowLayer;
58 
59 /** 隐藏辉光 */
60 -(void)hideGlowLayer;
61 
62 /** 开始循环辉光动画 */
63 -(void)startGlowAnimation;
64 
65 /** 暂停辉光动画 */
66 -(void)pauseGlowAnimation;
67 
68 /** 重启辉光动画 */
69 -(void)reStareGlowAnimation;
70 
71 @end
72 
73 @interface UIView (GlowViews)
74 
75 /** GlowLayer */
76 @property (nonatomic,strong)GlowLayer *glowLayer;
77 
78 
79 /** 创建GlowLayer,默认辉光颜色为红色 */
80 -(void)addGlowLayer;
81 /** 创建GlowLayer,需要设置辉光颜色 */
82 -(void)addGlowLayerWithGlowColor:(UIColor*)glowColor;
83 
84 /** 插入辉光 */
85 -(void)insertGlowLayerToSuperlayer;
86 
87 /** 完全移除GLowLayer */
88 -(void)removeGlowLayerFromSuperlayer;
89 @end
  1 //
  2 //  GlowLayer.m
  3 //  GlowView
  4 //
  5 //  Created by HEYANG on 16/1/30.
  6 //  Copyright © 2016年 HeYang. All rights reserved.
  7 //
  8 
  9 #import "GlowLayer.h"
 10 
 11 @interface GlowLayer ()
 12 
 13 /** 辉光的颜色 */
 14 @property (nonatomic,strong)UIColor *glowColor;
 15 
 16 /** 需要添加辉光效果的View ,注意这里用的是weak,而不是strong */
 17 @property (nonatomic,weak)UIView *addedGlowView;
 18 
 19 /** dispatch_source_t */
 20 @property (nonatomic,strong)dispatch_source_t timer;
 21 @end
 22 
 23 @implementation GlowLayer
 24 
 25 #pragma mark - 创建辉光
 26 
 27 // 遗留了一个先后顺序的问题,
 28 /** 在原始的View上创建出辉光layer */
 29 -(void)createGlowLayerWithOriginView:(UIView*)originView glowColor:(UIColor*)glowColor{
 30     self.glowColor = glowColor;
 31     // 创建一个图形上下文 参数:CGSize size:上下文的尺寸 BOOL opaque是否不透明 CGFloat scale缩放因子
 32     UIGraphicsBeginImageContextWithOptions(originView.bounds.size, NO, [UIScreen mainScreen].scale);
 33     // 通过get函数得到当前图形上下文,然后将origingView上的图形渲染到这个图形上下文上
 34     [originView.layer renderInContext:UIGraphicsGetCurrentContext()];
 35     // 创建贝塞尔曲线
 36     UIBezierPath *path = [UIBezierPath bezierPathWithRect:originView.bounds];
 37     // 设置贝塞尔取消绘制的颜色
 38     [self.glowColor setFill];//这里还是需要懒加载
 39     // 设置贝塞尔曲线绘制模式
 40     [path fillWithBlendMode:kCGBlendModeSourceAtop alpha:1];
 41     
 42     
 43     // 设置self(GlowLayer)初始状态
 44     self.frame = originView.bounds;
 45     // 至少要在设置好当前frame值之后,然后添加图形上下文的Image
 46     // 获得当前图形上下文的图形,然后赋值给CALayer的constraints
 47     self.contents = (__bridge id _Nullable)(UIGraphicsGetImageFromCurrentImageContext().CGImage);
 48 
 49     // 阴影设置不透明,其他的设置为透明
 50     self.opacity = 0.f;
 51     self.shadowOpacity = 1.f;
 52     // 阴影偏移量为(0,0)
 53     self.shadowOffset = CGSizeMake(0, 0);
 54     
 55     
 56     // 关闭图形上下文
 57     UIGraphicsEndImageContext();
 58     
 59     // 强引用指向这个原来的View
 60     self.addedGlowView = originView;
 61 }
 62 
 63 
 64 
 65 #pragma mark - 显示和隐藏辉光
 66 
 67 /** 显示辉光 */
 68 -(void)showGLowLayer{
 69     // 设置阴影初始效果
 70     self.shadowColor = self.glowColor.CGColor;
 71     self.shadowRadius = self.glowRadius.floatValue;
 72     
 73     
 74     CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
 75     animation.fromValue = @(0);
 76     animation.toValue = self.glowOpacity;
 77     animation.duration = self.glowAnimationDuration.floatValue;
 78     // 设置最终值
 79     self.opacity = self.glowOpacity.floatValue;
 80     
 81     [self addAnimation:animation forKey:nil];
 82 }
 83 
 84 /** 隐藏辉光 */
 85 -(void)hideGlowLayer{
 86     self.shadowColor = self.glowColor.CGColor;
 87     self.shadowRadius = self.glowRadius.floatValue;
 88     
 89     CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
 90     animation.fromValue = self.glowOpacity;
 91     animation.toValue = @(0);
 92     animation.duration = self.glowAnimationDuration.floatValue;
 93     // 设置最终值
 94     self.opacity = 0;
 95     
 96     [self addAnimation:animation forKey:nil];
 97 }
 98 
 99 #pragma mark - 循环显示和隐藏辉光
100 
101 /** 开始循环辉光动画 */
102 -(void)startGlowAnimation{
103     CGFloat cycleTime = self.glowAnimationDuration.floatValue * 2
104     + self.glowDuration.floatValue + self.hideDuration.floatValue;
105     CGFloat delayTime = self.glowAnimationDuration.floatValue + self.glowDuration.floatValue;
106     
107     _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
108     dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, cycleTime * NSEC_PER_SEC, 0);
109     dispatch_source_set_event_handler(_timer, ^{
110         [self showGLowLayer];
111         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
112             [self hideGlowLayer];
113         });
114     });
115     dispatch_resume(_timer);
116 }
117 /** 暂停辉光动画 */
118 -(void)pauseGlowAnimation{
119     [self removeFromSuperlayer];
120 }
121 /** 重启辉光动画 */
122 -(void)reStareGlowAnimation{
123     [self.addedGlowView.layer addSublayer:self];
124     [self startGlowAnimation];
125 }
126 
127 #pragma mark - 懒加载辉光的效果,同时处理数据越界问题
128 #pragma mark duration 辉光时间
129 -(NSNumber *)glowDuration{
130     if (!_glowDuration || _glowDuration.floatValue < 0) {
131         _glowDuration = @(0.5f);
132     }
133     return _glowDuration;
134 }
135 -(NSNumber *)hideDuration{
136     if (!_hideDuration || _hideDuration.floatValue < 0) {
137         _hideDuration = @(0.5);
138     }
139     return _hideDuration;
140 }
141 -(NSNumber *)glowAnimationDuration{
142     if (!_glowDuration || _glowDuration.floatValue < 0) {
143         _glowDuration = @(1.f);
144     }
145     return _glowDuration;
146 }
147 #pragma mark 辉光颜色
148 -(UIColor *)glowColor{
149     if (!_glowColor) {
150         _glowColor = [UIColor redColor];
151     }
152     return _glowColor;
153 }
154 #pragma mark 辉光半径
155 -(NSNumber *)glowRadius{
156     if (!_glowRadius || _glowRadius.floatValue <= 0) {
157         _glowRadius = @(2.f);
158     }
159     return _glowRadius;
160 }
161 #pragma mark 辉光透明度
162 -(NSNumber *)glowOpacity{
163     if (!_glowOpacity || _glowOpacity.floatValue <= 0) {
164         _glowOpacity = @(0.8);
165     }
166     return _glowOpacity;
167 }
168 @end
169 
170 #import <objc/runtime.h>
171 
172 @implementation UIView (GlowViews)
173 
174 /** 创建GlowLayer,默认辉光颜色为红色 */
175 -(void)addGlowLayer{
176     [self addGlowLayerWithGlowColor:nil];
177 }
178 /** 创建GlowLayer,需要设置辉光颜色 */
179 -(void)addGlowLayerWithGlowColor:(UIColor*)glowColor{
180     if (self.glowLayer == nil) {
181         self.glowLayer = [[GlowLayer alloc] init];
182     }
183     [self.glowLayer createGlowLayerWithOriginView:self glowColor:glowColor];
184     [self insertGlowLayerToSuperlayer];
185 }
186 #pragma mark - 插入和移除辉光
187 
188 /** 插入辉光 */
189 -(void)insertGlowLayerToSuperlayer{
190     if (self.glowLayer == nil) {
191         self.glowLayer = [[GlowLayer alloc] init];
192     }
193     [self.layer addSublayer:self.glowLayer];
194 }
195 
196 
197 /** 移除辉光 */
198 -(void)removeGlowLayerFromSuperlayer{
199     [self.glowLayer removeFromSuperlayer];
200     self.glowLayer = nil;
201 }
202 
203 #pragma mark - Runtime动态添加属性
204 NSString * const _recognizerGlowLayer = @"_recognizerGlowLayer";
205 -(void)setGlowLayer:(GlowLayer *)glowLayer{
206     objc_setAssociatedObject(self, (__bridge const void *)(_recognizerGlowLayer), glowLayer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
207 }
208 -(GlowLayer *)glowLayer{
209     return objc_getAssociatedObject(self, (__bridge const void *)(_recognizerGlowLayer));
210 }
211 
212 
213 @end

使用实例:

 转载注明出处:http://www.cnblogs.com/goodboy-heyang/p/5172807.html,尊重劳动成果哦。

原文地址:https://www.cnblogs.com/goodboy-heyang/p/5172807.html