iOS之UI--辉光动画

简介:

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

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

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

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

先展示效果图:

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

源码:

//
//  GlowLayer.h
//  GlowView
//
//  Created by HEYANG on 16/1/30.
//  Copyright © 2016年 HeYang. All rights reserved.
//

#import <UIKit/UIKit.h>

//                                     == 动画时间解析 ==
//
//  0.0 ----------- 0.0 ------------> glowOpacity [---------------] glowOpacity ------------> 0.0
//           T                T                           T                           T
//           |                |                           |                           |
//           |                |                           |                           |
//           .                .                           .                           .
//     hideDuration   animationDuration              glowDuration              animationDuration
//

/**
 *  需要考虑的参数
 *  
 *  需要考虑的逻辑
 *      1.数值越界问题,通过懒加载
 *      2.动画时间的安排(看前面的动画时间的解析)
 *
 *  需要对外公开的接口
 */


@interface GlowLayer : CALayer

#pragma mark - 对外公开的属性

#pragma mark 设置辉光效果
/** 辉光的阴影半径 */
@property (nonatomic,strong)NSNumber *glowRadius;
/** 辉光的透明度 */
@property (nonatomic,strong)NSNumber *glowOpacity;

#pragma mark 设置辉光的时间
/** 保持辉光的时间,默认设置为0.5f */
@property (nonatomic,strong)NSNumber *glowDuration;
/** 不显示辉光的时间,默认设置为0.5f */
@property (nonatomic,strong)NSNumber *hideDuration;
/** 辉光的变化时间,从明到暗或者是从暗到明,默认设置为1.f */
@property (nonatomic,strong)NSNumber *glowAnimationDuration;


#pragma mark - 对外公开的接口

/** 在原始的View上创建出辉光layer */
-(void)createGlowLayerWithOriginView:(UIView*)originView glowColor:(UIColor*)glowColor;

/** 显示辉光 */
-(void)showGLowLayer;

/** 隐藏辉光 */
-(void)hideGlowLayer;

/** 开始循环辉光动画 */
-(void)startGlowAnimation;

/** 暂停辉光动画 */
-(void)pauseGlowAnimation;

/** 重启辉光动画 */
-(void)reStareGlowAnimation;

@end

@interface UIView (GlowViews)

/** GlowLayer */
@property (nonatomic,strong)GlowLayer *glowLayer;


/** 创建GlowLayer,默认辉光颜色为红色 */
-(void)addGlowLayer;
/** 创建GlowLayer,需要设置辉光颜色 */
-(void)addGlowLayerWithGlowColor:(UIColor*)glowColor;

/** 插入辉光 */
-(void)insertGlowLayerToSuperlayer;

/** 完全移除GLowLayer */
-(void)removeGlowLayerFromSuperlayer;
@end


//
//  GlowLayer.m
//  GlowView
//
//  Created by HEYANG on 16/1/30.
//  Copyright © 2016年 HeYang. All rights reserved.
//

#import "GlowLayer.h"

@interface GlowLayer ()

/** 辉光的颜色 */
@property (nonatomic,strong)UIColor *glowColor;

/** 需要添加辉光效果的View ,注意这里用的是weak,而不是strong */
@property (nonatomic,weak)UIView *addedGlowView;

/** dispatch_source_t */
@property (nonatomic,strong)dispatch_source_t timer;
@end

@implementation GlowLayer

#pragma mark - 创建辉光

// 遗留了一个先后顺序的问题,
/** 在原始的View上创建出辉光layer */
-(void)createGlowLayerWithOriginView:(UIView*)originView glowColor:(UIColor*)glowColor{
    self.glowColor = glowColor;
    // 创建一个图形上下文 参数:CGSize size:上下文的尺寸 BOOL opaque是否不透明 CGFloat scale缩放因子
    UIGraphicsBeginImageContextWithOptions(originView.bounds.size, NO, [UIScreen mainScreen].scale);
    // 通过get函数得到当前图形上下文,然后将origingView上的图形渲染到这个图形上下文上
    [originView.layer renderInContext:UIGraphicsGetCurrentContext()];
    // 创建贝塞尔曲线
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:originView.bounds];
    // 设置贝塞尔取消绘制的颜色
    [self.glowColor setFill];//这里还是需要懒加载
    // 设置贝塞尔曲线绘制模式
    [path fillWithBlendMode:kCGBlendModeSourceAtop alpha:1];
    
    
    // 设置self(GlowLayer)初始状态
    self.frame = originView.bounds;
    // 至少要在设置好当前frame值之后,然后添加图形上下文的Image
    // 获得当前图形上下文的图形,然后赋值给CALayer的constraints
    self.contents = (__bridge id _Nullable)(UIGraphicsGetImageFromCurrentImageContext().CGImage);

    // 阴影设置不透明,其他的设置为透明
    self.opacity = 0.f;
    self.shadowOpacity = 1.f;
    // 阴影偏移量为(0,0)
    self.shadowOffset = CGSizeMake(0, 0);
    
    
    // 关闭图形上下文
    UIGraphicsEndImageContext();
    
    // 强引用指向这个原来的View
    self.addedGlowView = originView;
}



#pragma mark - 显示和隐藏辉光

/** 显示辉光 */
-(void)showGLowLayer{
    // 设置阴影初始效果
    self.shadowColor = self.glowColor.CGColor;
    self.shadowRadius = self.glowRadius.floatValue;
    
    
    CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    animation.fromValue = @(0);
    animation.toValue = self.glowOpacity;
    animation.duration = self.glowAnimationDuration.floatValue;
    // 设置最终值
    self.opacity = self.glowOpacity.floatValue;
    
    [self addAnimation:animation forKey:nil];
}

/** 隐藏辉光 */
-(void)hideGlowLayer{
    self.shadowColor = self.glowColor.CGColor;
    self.shadowRadius = self.glowRadius.floatValue;
    
    CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    animation.fromValue = self.glowOpacity;
    animation.toValue = @(0);
    animation.duration = self.glowAnimationDuration.floatValue;
    // 设置最终值
    self.opacity = 0;
    
    [self addAnimation:animation forKey:nil];
}

#pragma mark - 循环显示和隐藏辉光

/** 开始循环辉光动画 */
-(void)startGlowAnimation{
    CGFloat cycleTime = self.glowAnimationDuration.floatValue * 2
    + self.glowDuration.floatValue + self.hideDuration.floatValue;
    CGFloat delayTime = self.glowAnimationDuration.floatValue + self.glowDuration.floatValue;
    
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, cycleTime * NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(_timer, ^{
        [self showGLowLayer];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self hideGlowLayer];
        });
    });
    dispatch_resume(_timer);
}
/** 暂停辉光动画 */
-(void)pauseGlowAnimation{
    [self removeFromSuperlayer];
}
/** 重启辉光动画 */
-(void)reStareGlowAnimation{
    [self.addedGlowView.layer addSublayer:self];
    [self startGlowAnimation];
}

#pragma mark - 懒加载辉光的效果,同时处理数据越界问题
#pragma mark duration 辉光时间
-(NSNumber *)glowDuration{
    if (!_glowDuration || _glowDuration.floatValue < 0) {
        _glowDuration = @(0.5f);
    }
    return _glowDuration;
}
-(NSNumber *)hideDuration{
    if (!_hideDuration || _hideDuration.floatValue < 0) {
        _hideDuration = @(0.5);
    }
    return _hideDuration;
}
-(NSNumber *)glowAnimationDuration{
    if (!_glowDuration || _glowDuration.floatValue < 0) {
        _glowDuration = @(1.f);
    }
    return _glowDuration;
}
#pragma mark 辉光颜色
-(UIColor *)glowColor{
    if (!_glowColor) {
        _glowColor = [UIColor redColor];
    }
    return _glowColor;
}
#pragma mark 辉光半径
-(NSNumber *)glowRadius{
    if (!_glowRadius || _glowRadius.floatValue <= 0) {
        _glowRadius = @(2.f);
    }
    return _glowRadius;
}
#pragma mark 辉光透明度
-(NSNumber *)glowOpacity{
    if (!_glowOpacity || _glowOpacity.floatValue <= 0) {
        _glowOpacity = @(0.8);
    }
    return _glowOpacity;
}
@end

#import <objc/runtime.h>

@implementation UIView (GlowViews)

/** 创建GlowLayer,默认辉光颜色为红色 */
-(void)addGlowLayer{
    [self addGlowLayerWithGlowColor:nil];
}
/** 创建GlowLayer,需要设置辉光颜色 */
-(void)addGlowLayerWithGlowColor:(UIColor*)glowColor{
    if (self.glowLayer == nil) {
        self.glowLayer = [[GlowLayer alloc] init];
    }
    [self.glowLayer createGlowLayerWithOriginView:self glowColor:glowColor];
    [self insertGlowLayerToSuperlayer];
}
#pragma mark - 插入和移除辉光

/** 插入辉光 */
-(void)insertGlowLayerToSuperlayer{
    if (self.glowLayer == nil) {
        self.glowLayer = [[GlowLayer alloc] init];
    }
    [self.layer addSublayer:self.glowLayer];
}


/** 移除辉光 */
-(void)removeGlowLayerFromSuperlayer{
    [self.glowLayer removeFromSuperlayer];
    self.glowLayer = nil;
}

#pragma mark - Runtime动态添加属性
NSString * const _recognizerGlowLayer = @"_recognizerGlowLayer";
-(void)setGlowLayer:(GlowLayer *)glowLayer{
    objc_setAssociatedObject(self, (__bridge const void *)(_recognizerGlowLayer), glowLayer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(GlowLayer *)glowLayer{
    return objc_getAssociatedObject(self, (__bridge const void *)(_recognizerGlowLayer));
}


@end

使用实例:

相关文章
|
iOS开发
iOS 动画绘制圆形
iOS 动画绘制圆形
100 1
|
编译器 iOS开发 异构计算
读iOS核心动画笔记
读iOS核心动画笔记
71 0
|
3月前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户点击按钮时,按钮将从圆形变为椭圆形,颜色从蓝色渐变到绿色;释放按钮时,动画以相反方式恢复。通过UIView的动画方法和弹簧动画效果,实现平滑自然的过渡。
94 1
|
4月前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
【10月更文挑战第18天】本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户按下按钮时,按钮将从圆形变为椭圆形并从蓝色渐变为绿色;释放按钮时,动画恢复原状。通过UIView的动画方法和弹簧动画效果,实现平滑自然的动画过渡。
79 5
|
5月前
|
Swift iOS开发 UED
揭秘一款iOS应用中令人惊叹的自定义动画效果,带你领略编程艺术的魅力所在!
【9月更文挑战第5天】本文通过具体案例介绍如何在iOS应用中使用Swift与UIKit实现自定义按钮动画,当用户点击按钮时,按钮将从圆形变为椭圆形并从蓝色渐变到绿色,释放后恢复原状。文中详细展示了代码实现过程及动画平滑过渡的技巧,帮助读者提升应用的视觉体验与特色。
87 11
|
5月前
|
前端开发 图形学 开发者
【独家揭秘】那些让你的游戏瞬间鲜活起来的Unity UI动画技巧:从零开始打造动态按钮,提升玩家交互体验的绝招大公开!
【9月更文挑战第1天】在游戏开发领域,Unity 是最受欢迎的游戏引擎之一,其强大的跨平台发布能力和丰富的功能集让开发者能够迅速打造出高质量的游戏。优秀的 UI 设计对于游戏至关重要,尤其是在手游市场,出色的 UI 能给玩家留下深刻的第一印象。Unity 的 UGUI 系统提供了一整套解决方案,包括 Canvas、Image 和 Button 等组件,支持添加各种动画效果。
303 3
|
6月前
|
Swift iOS开发 UED
【绝妙创意】颠覆你的视觉体验!揭秘一款iOS应用中令人惊叹的自定义动画效果,带你领略编程艺术的魅力所在!
【8月更文挑战第13天】本文通过一个具体案例,介绍如何使用Swift与UIKit在iOS应用中创建独特的按钮动画效果。当按钮被按下时,其形状从圆形变化为椭圆形,颜色则从蓝色渐变为绿色;释放后,动画反向恢复原状。利用UIView动画方法及弹簧动画效果,实现了平滑自然的过渡。通过调整参数,开发者可以进一步优化动画体验,增强应用的互动性和视觉吸引力。
74 7
|
6月前
|
开发者 图形学 前端开发
绝招放送:彻底解锁Unity UI系统奥秘,五大步骤教你如何缔造令人惊叹的沉浸式游戏体验,从Canvas到动画,一步一个脚印走向大师级UI设计
【8月更文挑战第31天】随着游戏开发技术的进步,UI成为提升游戏体验的关键。本文探讨如何利用Unity的UI系统创建美观且功能丰富的界面,包括Canvas、UI元素及Event System的使用,并通过具体示例代码展示按钮点击事件及淡入淡出动画的实现过程,助力开发者打造沉浸式的游戏体验。
181 0
|
6月前
|
测试技术 Swift iOS开发
探索iOS自动化测试:使用Swift编写UI测试
【8月更文挑战第31天】在软件开发的海洋中,自动化测试是保证船只不偏离航线的灯塔。本文将带领读者启航,深入探索iOS应用的自动化UI测试。我们将通过Swift语言,点亮代码的灯塔,照亮测试的道路。文章不仅会展示如何搭建测试环境,还会提供实用的代码示例,让理论知识在实践中生根发芽。无论你是新手还是有经验的开发者,这篇文章都将是你技能提升之旅的宝贵指南。
|
iOS开发
iOS 常用阅读软件打开书籍的转场动画
iOS 常用阅读软件打开书籍的转场动画
115 0

热门文章

最新文章

  • 1
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 2
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 3
    用自然语言控制电脑,字节跳动开源 UI-TARS 的桌面版应用!内附详细的安装和配置教程
  • 4
    UI-TARS:字节跳动开源专注于多平台 GUI 自动化交互的视觉语言模型
  • 5
    【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 6
    移动端UI名词 - AxureMost
  • 7
    【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
  • 8
    unity判断鼠标在不在UI上
  • 9
    iOS8 中无需开源库的内置功能一览
  • 10
    iOS7应用开发7:自定义视图、手势操作