第九篇:基于定时器的动画

2018-01-22  本文已影响13人  意一ineyee

目录

一、定时器动画不用NSTimer的理由

二、使用CADisplayLink来做定时器动画

三、计算每帧的持续时间


一、定时器动画不用NSTimer的理由

二、使用CADisplayLink来做定时器动画

举例:
(清单4.1)

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height

@interface ViewController ()

@property (strong, nonatomic) UIView *contentView;
@property (strong, nonatomic) CAShapeLayer *layer1;

@property (strong, nonatomic) CADisplayLink *displayLink;// CADisplayLink和NSTimer差不多,注意事项也差不多
@property (assign, nonatomic) float waveAmplitude;// 振幅
@property (assign, nonatomic) float waveSpeed;// 波纹流动的速度
@property (assign, nonatomic) float waveOffset;// 初相

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self initialize];
    [self layoutUI];
    [self startWave];
}


#pragma mark - private method

- (void)startWave {

    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(wave:)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)stopWave {

    [self.displayLink invalidate];
    self.displayLink = nil;
}

- (void)wave:(CADisplayLink *)displayLink {

    self.waveOffset += self.waveSpeed;

    // 绘制第一条贝塞尔曲线
    UIBezierPath *path1 = [[UIBezierPath alloc] init];
    // 起始点
    [path1 moveToPoint:CGPointMake(0, self.waveAmplitude)];// 起始点
    // 遍历所有的x坐标,根据公式求出所有的y坐标,从而得到所有的点,贝塞尔曲线将它们连起来
    for (CGFloat x = 0.0; x < kScreenWidth; x ++) {

        CGFloat y = self.waveAmplitude * sinf(3 * M_PI * x / kScreenWidth + self.waveOffset * M_PI / kScreenWidth);
        [path1 addLineToPoint:CGPointMake(x, y)];
    }
    // 将贝塞尔曲线赋值给shapeLayer的path就可以了
    self.layer1.path = path1.CGPath;
}


#pragma mark - layoutUI

- (void)layoutUI {

    [self.view addSubview:self.contentView];
    [self.contentView.layer addSublayer:self.layer1];
}


#pragma mark - setter, getter

- (UIView *)contentView {

    if (_contentView == nil) {

        _contentView = [[UIView alloc] init];
        _contentView.frame = CGRectMake(0, kScreenHeight - 200, kScreenWidth, 200);
        _contentView.backgroundColor = [UIColor yellowColor];
    }

    return _contentView;
}

- (CAShapeLayer *)layer1 {

    if (_layer1 == nil) {

        _layer1 = [CAShapeLayer layer];
        _layer1.strokeColor = [UIColor redColor].CGColor;
        _layer1.fillColor = [UIColor clearColor].CGColor;
        _layer1.lineWidth =  5;
        _layer1.lineCap = kCALineCapRound;
        _layer1.lineJoin = kCALineJoinRound;
    }

    return _layer1;
}


#pragma mark - initialize

- (void)initialize {

    // 初始值
    self.waveAmplitude = 20;
    self.waveSpeed = 2.0;
    self.waveOffset = 0.0;
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
1.gif

三、计算每帧的持续时间

但即便是使用了CADisplayLink,我们也不能保证动画就不掉帧了,因为有可能一帧动画的执行时长有可能超过1/60秒,这种情况下我们就需要自己计算每帧的持续时间,代替硬编码的1/60秒了。具体学习可参看原书第11章。

上一篇 下一篇

猜你喜欢

热点阅读