关键帧动画,动画组实现文字效果

动画效果

拆分动画

实现一个动画,有很多种途径。不管是哪种途径,都要分析一下动画由哪几部分组成,然后将这些部分组合起来。
这是一个简单的动画,由两部分组成:

  • 缩放动画,字体框架大小的缩放
  • 旋转动画,字体放大到最大时,左右旋转,实现抖动效果

最后用动画组将这两组动画组合起来就OK了。

旋转动画

- (void)rotationAnimation {
    CAKeyframeAnimation *rotationAnim = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
    // 动画时间
    rotationAnim.duration =3.0;
    //无限次重复
    rotationAnim.repeatCount =MAXFLOAT;
    // 保持最后的状态
    rotationAnim.removedOnCompletion =NO;
    //设置抖动数值
    rotationAnim.values =@[@(ANGLE_TO_RADIAN(0)),@(ANGLE_TO_RADIAN(0)),@(ANGLE_TO_RADIAN(-7)),@(ANGLE_TO_RADIAN(7)),@(ANGLE_TO_RADIAN(0)),@(ANGLE_TO_RADIAN(0))];
    rotationAnim.keyTimes = @[@(0), @(0.4), @(0.47), @(0.52), @(0.6), @(1.0)];
    //动画的填充模式
    rotationAnim.fillMode =kCAFillModeForwards;

    //layer层实现动画

    [self.searchLayer addAnimation:rotationAnim forKey:@"shake"];

}

缩放动画

- (void)scaleAnimation {
    CAKeyframeAnimation *scaleAnim = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
    scaleAnim.repeatCount = MAXFLOAT;
    scaleAnim.duration = 3.0f;
    scaleAnim.removedOnCompletion = NO;
    scaleAnim.values = @[@(1.0),@(1.0), @(1.2), @(1.2),@(1.0),@(1.0)];
    scaleAnim.keyTimes = @[@(0), @(0.2), @(0.3), @(0.7), @(0.8), @(1.0)];
    scaleAnim.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
    [self.searchLayer addAnimation:scaleAnim forKey:@"bouce"];

}

整体实现

分别实现之后,用动画组将他们组合起来。
效果上显示字体放大后执行旋转动画,这里我采用关键帧动画的keyTimes来协调的。因为Apple并不建议在一个动画completion回调里执行另一个动画。
PS:
当这个button绑定的点击方法需要跳转VC时,可以设置动画组的 removedOnCompletion 属性为 NO 来让 VC 切换不停止动画。

//继承自UIButton
@interface ShakeButton : UIButton

@end

//
//  ShakeButton.m
//  HtmlLoad
//
//  Created by zchao on 2018/3/21.
//  Copyright © 2018年 zchao. All rights reserved.
//

#import "ShakeButton.h"

#define BoardWidth 2.0f
#define margin 8.0f

#define ANGLE_TO_RADIAN(angle) ((angle)/180.0 * M_PI)


@interface ShakeButton ()

@property(nonatomic, strong) CALayer *searchLayer;
@end

@implementation ShakeButton

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

        //添加图层到根图层
        CGFloat x = (2-sqrtf(2))*0.25 * frame.size.width + 0.5*sqrtf(2)*BoardWidth;
        CGFloat width = sqrt(2)*0.5*frame.size.width - sqrtf(2)*BoardWidth;

        [self.layer addSublayer:[self drawSearchLayer:CGRectMake(x, x, width, width)]];
        [self startAnimation];
        //        [self scaleAnimation];
        //        [self rotationAnimation];
    }
    return self;
}


- (void)startAnimation {

    CAKeyframeAnimation *rotationAnim = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
    // 动画时间
    rotationAnim.duration =3.0;
    //无限次重复
    rotationAnim.repeatCount =MAXFLOAT;
    // 保持最后的状态
    rotationAnim.removedOnCompletion =NO;
    //设置抖动数值
    rotationAnim.values =@[@(ANGLE_TO_RADIAN(0)),@(ANGLE_TO_RADIAN(0)),@(ANGLE_TO_RADIAN(-7)),@(ANGLE_TO_RADIAN(7)),@(ANGLE_TO_RADIAN(0)),@(ANGLE_TO_RADIAN(0))];
    rotationAnim.keyTimes = @[@(0), @(0.4), @(0.47), @(0.52), @(0.6), @(1.0)];
    //动画的填充模式
    rotationAnim.fillMode =kCAFillModeForwards;

    CAKeyframeAnimation *scaleAnim = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
    scaleAnim.repeatCount = MAXFLOAT;
    scaleAnim.duration = 3.0f;
    scaleAnim.removedOnCompletion = NO;
    scaleAnim.values = @[@(1.0),@(1.0), @(1.2), @(1.2),@(1.0),@(1.0)];
    scaleAnim.keyTimes = @[@(0), @(0.2), @(0.3), @(0.7), @(0.8), @(1.0)];
    scaleAnim.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];

    CAAnimationGroup *group = [CAAnimationGroup animation];
    group.duration = 3.0f;
    group.repeatCount = MAXFLOAT;
    group.animations = @[rotationAnim, scaleAnim];
    group.removedOnCompletion = NO;
    [self.searchLayer addAnimation:group forKey:@"fuck"];

}

- (void)scaleAnimation {
    CAKeyframeAnimation *scaleAnim = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
    scaleAnim.repeatCount = MAXFLOAT;
    scaleAnim.duration = 3.0f;
    scaleAnim.removedOnCompletion = NO;
    scaleAnim.values = @[@(1.0),@(1.0), @(1.2), @(1.2),@(1.0),@(1.0)];
    scaleAnim.keyTimes = @[@(0), @(0.2), @(0.3), @(0.7), @(0.8), @(1.0)];
    scaleAnim.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
    [self.searchLayer addAnimation:scaleAnim forKey:@"bouce"];

}


- (void)rotationAnimation {
    CAKeyframeAnimation *rotationAnim = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
    // 动画时间
    rotationAnim.duration =3.0;
    //无限次重复
    rotationAnim.repeatCount =MAXFLOAT;
    // 保持最后的状态
    rotationAnim.removedOnCompletion =NO;
    //设置抖动数值
    rotationAnim.values =@[@(ANGLE_TO_RADIAN(0)),@(ANGLE_TO_RADIAN(0)),@(ANGLE_TO_RADIAN(-7)),@(ANGLE_TO_RADIAN(7)),@(ANGLE_TO_RADIAN(0)),@(ANGLE_TO_RADIAN(0))];
    rotationAnim.keyTimes = @[@(0), @(0.4), @(0.47), @(0.52), @(0.6), @(1.0)];
    //动画的填充模式
    rotationAnim.fillMode =kCAFillModeForwards;

    //layer层实现动画

    [self.searchLayer addAnimation:rotationAnim forKey:@"shake"];

}

//Only override drawRect: if you perform custom drawing. An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    //Drawing code
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextAddArc(context, rect.size.width/2, rect.size.height/2, rect.size.width/2-BoardWidth, 0, 2*M_PI, 0);
    CGPoint aPoints[2];
    aPoints[0] =CGPointMake(rect.size.width*(0.5+sqrtf(2)/4), rect.size.width*(0.5+sqrtf(2)/4));
    aPoints[1] =CGPointMake(rect.size.width, rect.size.height);
    CGContextAddLines(context, aPoints, 2);
    //画笔颜色
    CGContextSetRGBStrokeColor(context, 1, 1, 1, 1.0);
    //线条粗细
    CGContextSetLineWidth(context, BoardWidth);
    CGContextDrawPath(context, kCGPathStroke);
}


- (CALayer *)drawSearchLayer:(CGRect)rect {
    //自定义图层
    CATextLayer *layer = [[CATextLayer alloc] init];
    self.searchLayer = layer;
    layer.frame = rect;
    layer.foregroundColor = RGBACOLOR(255, 184, 62, 1).CGColor;
    layer.string = @"搜";

    UIFont *font = [UIFont boldSystemFontOfSize:11];
    CFStringRef fontName = (__bridge CFStringRef)font.fontName;
    CGFontRef fontRef =CGFontCreateWithFontName(fontName);
    layer.font = fontRef;
    layer.fontSize = font.pointSize;
    CGFontRelease(fontRef);
    layer.contentsScale = [UIScreen mainScreen].scale;
    layer.alignmentMode = kCAAlignmentCenter;

    return layer;
}


@end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值