iOS-小小demo封装View--利用动画和贝塞尔实现咻咻效果

楚天千里清秋,水随天去秋无际!<超音蝠>

先上效果图:


圆形

方形

  • 思路分析:

这四种风格其实就是两种, 一种是动画效果在视图View的内部, 另一种是在视图的外部! 我们可以尝试封装自定义 View 设置相关属性去实现这两个风格. 点击时候触及动画, 说明要在这个 View 上添加手势! 分析动画效果其实是两种, 第一种是视图的比例由小到大,第二种是动画显示效果是渐渐变暗! 那么我们可以把两种效果写到一个动画组中!还有一个问题是效果的形状, 也就是 Layer 动画展示的形状有方形有圆形, 这个形状就需要我们思考如何去绘制和判断!

  • 代码分析:

  • 首先要创建自定义一个 View 类去实现点击有动画的效果! 因为分析有两种风格(在外在内)的动画, 因此要在. h 文件中声明属性去接收外界告知的风格! 我们还可以添加一些供外界修改的值, 比如动画的边界粗细, 填充颜色, 动画时间等等这里我用一个颜色举例! 外界可提供一个颜色, 怎么用具体代码中有!

typedef NS_ENUM(NSUInteger, FlashButtonType){
    # 风格定义一个枚举类型的去表示 分别是代表动画在里面和外面 (便于理解)
    DDFlashButtonInner = 0,
    DDFlashButtonOuter = 1
    
};
# 定义的两个属性
@property (strong, nonatomic) UIColor *flashColor;
@property (assign, nonatomic) FlashButtonType buttonType;

# 写这个方法可以对 View 的子视图上的子控件进行操作, 可以不把子控件都暴露出去
- (void)setText:(NSString *)text withTextColor:(UIColor *)textColor;
  • 第 2 步: 在初始化方法中,我们可以给这个 view 加一些子视图比如 UILabel 去显示一些想表达的文字(这里还可以写个方法去改变 label上 text 的属性,)! 还需要给 View 添加点击手势!
- (instancetype) initWithFrame:(CGRect)frame{
    
    if (self = [super initWithFrame:frame]) {
# 创建手势  并添加到 View 上
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap:)];
         [self addGestureRecognizer:tap];
        self.textLabel = [[UILabel alloc] initWithFrame:self.bounds];
        self.textLabel.backgroundColor = [UIColor clearColor];
        [self.textLabel setTextAlignment:NSTextAlignmentCenter];
        [self addSubview:self.textLabel];
        self.backgroundColor = [UIColor cyanColor];
# 给一个默认的风格  不设置就是代表 动画在里面
       self.buttonType = DDFlashButtonInner;
    }    
    return self;
}
  • 第 3 步: 可以给子控件给一些属性 这里有 label 还写了个方法
- (void)setText:(NSString *)text withTextColor:(UIColor *)textColor
{
# 就是给 Label 赋外界传来的值  若有其他的控件可以改一些参数用此方法
    if (text)
    {
        [self.textLabel setText:text];
    }
    if (textColor)
    {
        [self.textLabel setTextColor:textColor];
    }
}
  • 第 4 步: 根据风格的不同我们要控制动画展示的范围, 也就是加入动画在内部就不能超过 View 的范围
# 这里就是重写了ButtonType setter方法,同时判断一下风格根据风格选择是否把超过视图 View 的部分裁剪掉
- (void)setButtonType:(FlashButtonType)buttonType
{
    _buttonType = buttonType;
       if (buttonType == DDFlashButtonInner)
    {
// 内容和子视图是夹在视图的边界内 ( 只允许 view范围内有子视图和类容可以显示 )
        self.clipsToBounds = 1;
    }else
    {// 外面可以显示
        self.clipsToBounds = 0;
    }
}
  • 第 5 步: 准备工作做好后, 一个思路就是去写点击事件, 需要什么就去创建什么! 这先去思考点击事件中需要的东西, 都满足之后再去写完善点击事件! 动画效果首先需要动画, 另外还需要能添加动画的 Layer;首先写个得到动画的方法!
- (CAAnimationGroup *)createFlashAnimationWisthScale:(CGFloat)scale
                                            duration:(CGFloat)duratiton
{
# 创建按比例收缩变大的动画
// 指定要在渲染动画性能时的关键路径 也就是图形转换的方式 这里是按收缩比例  这里也可以不用.scale 因为我们初始值设置是根据CATransform3D
    CABasicAnimation  *scaleAnnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
// 动画开始点
    // 这个动画效果初值  就是本身的原始的位置
    scaleAnnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
    // 等价 scaleAnnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)];
// 动画结束点
    //  在 x 轴和 y 轴的变化比例
    scaleAnnimation.toValue = [NSValue valueWithCATransform3D:(CATransform3DMakeScale(scale, scale, 1))];

# 创建透明度变换的动画  
  CABasicAnimation *alphaAnimation = [CABasicAnimation  animationWithKeyPath:@"opacity"];
    alphaAnimation.fromValue = @1;
    alphaAnimation.toValue = @0;

#  创建动画组把上面两个动画加进去  
    CAAnimationGroup *animation = [CAAnimationGroup new];
    animation.animations = @[scaleAnnimation,alphaAnimation];
// 动画效果 (节奏, Timing Function的会被用于变化起点和终点之间的插值计算.形象点说是Timing Function决定了动画运行的节奏(Pacing),比如是均匀变化(相同时间变化量相同),先快后慢,先慢后快还是先慢再快再慢.)
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
 
# 返回我们想要的动画效果组  
    return animation;
}
  • 第 6 步: 得到一个CAShapeLayer 类型的图层(因为要结合贝塞尔曲线得到形状路径), 画一个形状那么就需要有位置
- (CAShapeLayer *)creatCircleShapWithPostion:(CGPoint)position
                                    pathRect:(CGRect)rect
                                      radius:(CGFloat)radius
{
    CAShapeLayer *circleShap = [CAShapeLayer layer];

// 从贝塞尔曲线取到形状
    circleShap.path = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:radius].CGPath;

// 虽然得到了形状, 但是并没有得到具体的 frame(bounds) 也就是实际上并没有范围  只是可以展现动画的效果  那么锚点其实就是设置的位置点
    circleShap.position = position;
    if (self.buttonType == DDFlashButtonInner)
    {
# 在这里设置 frame 就是为了满足我们想要的锚点位置让动画效果动起来, 下面也一样, 可以不设置试试效果就明白了!
      // circleShap.bounds = CGRectMake(0, 0, radius *2, radius *2);
      circleShap.frame = CGRectMake(position.x-radius, position.y-radius, radius*2, radius*2);
        // 线宽
        circleShap.lineWidth = 1;
        // 填充的颜色  不设置默认就给黄色
        circleShap.fillColor = self.flashColor ? self.flashColor.CGColor:[UIColor yellowColor].CGColor;

    }else
    {
         circleShap.frame = self.bounds;
     // 线宽
        circleShap.lineWidth = 5;
        circleShap.fillColor = [UIColor clearColor].CGColor;
    // 边缘线的颜色  不设置就默认给个紫色
    circleShap.strokeColor = self.flashColor ? self.flashColor.CGColor:[UIColor purpleColor].CGColor;
        
    }
   
    // 不透明度  要设置成透明的  不然内部风格的时候会画出来图案点点
    circleShap.opacity = 0;
    return circleShap;
}
  • 第 7 步 : 把点击的事件完成就 OK 了
- (void)didTap:(UITapGestureRecognizer *)tapGesture
{
// 获取点击点的位置
    CGPoint tapLocation = [tapGesture locationInView:self];
// 定义一个图层  下面分情况去给予不同形状   
 CAShapeLayer *circleShape = nil;
// 默认一个变化比例 1 倍
     CGFloat scale = 1.0f;
// 获取 View 的宽和高
     CGFloat width = self.bounds.size.width, height = self.bounds.size.height;
      if (self.buttonType == DDFlashButtonInner)
    {
# 这里就是在视图内部效果, 就是以点击的点为圆心 画一个小圆(这里是半径为1) 然后让它动画起来 (不断的变大并变透明) 所以放大倍数只要能到最大的变就行了 不一定非要这样写, 你开心就好!
       CGFloat biggerEdge = width > height ? width :height; 
       CGFloat radius = 1
       scale = biggerEdge / radius + 0.5;
# 调用方法获得图层 锚点位置就是点击的位置
circleShape = [self creatCircleShapWithPostion:CGPointMake(tapLocation.x , tapLocation.y ) pathRect:CGRectMake(0, 0, radius * 2, radius * 2) radius:radius];      
    }else
    {
# 这个是外部动画效果  设置能放大5.5倍
        scale = 5.5f;
# 锚点位置在 View 的中心  这个图层和 View 是一样的形状范围
     circleShape = [self creatCircleShapWithPostion:CGPointMake(width /2 , height / 2) pathRect:self.bounds radius:self.layer.cornerRadius];
      }
// view图层 上添加 有形状的自定义图层
    [self.layer addSublayer:circleShape];

# 给自定义图层添加动画    
    [circleShape addAnimation:[self createFlashAnimationWisthScale:scale duration:1.0f] forKey:nil];
}

最后说一句: 用的时候在 viewController 中引入, 创建自定义的 View 实例对象, 改变传入的风格和颜色就可以展示效果了!

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,799评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • 这周除了出去旅游忘记了拿跳绳,其余时间我每天都会在八点之前起床晨练。 就算出游我也没有忘记练习字帖 晨诵上周读完了...
    橄榄树尧阅读 315评论 2 1
  • Whether you use the Terminal occasionally or regularly, y...
    ifels阅读 825评论 0 1
  • 一 家阿萨德法师打发 1 克辣椒是地方 2 家卡上的减肥了看 闪亮的会计法 text这里是引用 的规范化的覆盖
    KrisWang77阅读 365评论 0 0