關鍵幀動畫,動畫組實現文字效果

動畫效果

拆分動畫

實現一個動畫,有很多種途徑。不管是哪種途徑,都要分析一下動畫由哪幾部分組成,然後將這些部分組合起來。
這是一個簡單的動畫,由兩部分組成:

  • 縮放動畫,字體框架大小的縮放
  • 旋轉動畫,字體放大到最大時,左右旋轉,實現抖動效果

最後用動畫組將這兩組動畫組合起來就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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章