欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-25 23:37:38
...

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

拆分动画

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

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

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

旋转动画

- (void)rotationAnimation {
    CAKeyframeAnimation *rotationAnim = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
    // 动画时间
    rotationAnim.duration =3.0;
    //无限次重复
    rotationAnim.repeatCount =MAXFLOAT;
    // 保持最后的状态
    rotationAnim.removedOnCompletion =NO;
    //设置抖动数值
    rotationAnim.values [email protected][@(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 [email protected][@(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 [email protected][@(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