[iOS Animation]CALayer-圖層時間-CAMediaTiming協議

圖層時間

時間和空間最大的區別在於,時間不能被複用 -- 弗斯特梅里克git

在上面兩章中,咱們探討了能夠用CAAnimation和它的子類實現的多種圖層動畫。動畫的發生是須要持續一段時間的,因此計時對整個概念來講相當重要。在這一章中,咱們來看看CAMediaTiming,看看Core Animation是如何跟蹤時間的。github

CAMediaTiming協議

 CAMediaTiming 協議定義了在一段動畫內用來控制逝去時間的屬性的集合,CALayerCAAnimation都實現了這個協議,因此時間能夠被任意基於一個圖層或者一段動畫的類控制。app

持續和重複

咱們在第八章「顯式動畫」中簡單提到過durationCAMediaTiming的屬性之一),duration是一個CFTimeInterval的類型(相似於NSTimeInterval的一種雙精度浮點類型),對將要進行的動畫的一次迭代指定了時間。ide

這裏的一次迭代是什麼意思呢?CAMediaTiming另外還有一個屬性叫作 repeatCount ,表明動畫重複的迭代次數。若是 duration 是2, repeatCount 設爲3.5(三個半迭代),那麼完整的動畫時長將是7秒。測試

durationrepeatCount默認都是0。但這不意味着動畫時長爲0秒,或者0次,這裏的0僅僅表明了「默認」,也就是0.25秒和1次,你能夠用一個簡單的測試來嘗試爲這兩個屬性賦多個值,如清單9.1,圖9.1展現了程序的結果。動畫

清單9.1 測試durationrepeatCountatom

複製代碼

@interface ViewController ()

@property (nonatomic, weak) IBOutlet UIView *containerView;
@property (nonatomic, weak) IBOutlet UITextField *durationField;
@property (nonatomic, weak) IBOutlet UITextField *repeatField;
@property (nonatomic, weak) IBOutlet UIButton *startButton;
@property (nonatomic, strong) CALayer *shipLayer;@end@implementation ViewController- (void)viewDidLoad
{
    [super viewDidLoad];    //add the ship
    self.shipLayer = [CALayer layer];
    self.shipLayer.frame = CGRectMake(0, 0, 128, 128);
    self.shipLayer.position = CGPointMake(150, 150);
    self.shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
    [self.containerView.layer addSublayer:self.shipLayer];
}- (void)setControlsEnabled:(BOOL)enabled
{    for (UIControl *control in @[self.durationField, self.repeatField, self.startButton]) {
        control.enabled = enabled;
        control.alpha = enabled? 1.0f: 0.25f;
    }
}- (IBAction)hideKeyboard
{
    [self.durationField resignFirstResponder];
    [self.repeatField resignFirstResponder];
}- (IBAction)start
{
    CFTimeInterval duration = [self.durationField.text doubleValue];    float repeatCount = [self.repeatField.text floatValue];    //animate the ship rotation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform.rotation";
    animation.duration = duration;
    animation.repeatCount = repeatCount;
    animation.byValue = @(M_PI * 2);
    animation.delegate = self;
    [self.shipLayer addAnimation:animation forKey:@"rotateAnimation"];    //disable controls    [self setControlsEnabled:NO];
}- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{    //reenable controls    [self setControlsEnabled:YES];
}@end

複製代碼

 

圖9.1

圖9.1 演示durationrepeatCount的測試程序spa

建立重複動畫的另外一種方式是使用 repeatDuration 屬性,它讓動畫重複一個指定的時間,而不是指定次數。你甚至設置一個叫作 autoreverses 的屬性(BOOL類型)在每次間隔交替循環過程當中自動回放。這對於播放一段連續非循環的動畫頗有用,例如打開一扇門,而後關上它(圖9.2)。code

圖9.2

圖9.2 擺動門的動畫orm

對門進行擺動的代碼見清單9.2。咱們用了autoreverses來使門在打開後自動關閉,在這裏咱們把repeatDuration設置爲INFINITY,因而動畫無限循環播放,設置repeatCountINFINITY也有一樣的效果。注意repeatCountrepeatDuration可能會相互衝突,因此你只要對其中一個指定非零值。對兩個屬性都設置非0值的行爲沒有被定義。

清單9.2 使用autoreverses屬性實現門的搖擺

複製代碼

@interface ViewController ()

@property (nonatomic, weak) UIView *containerView;@end@implementation ViewController- (void)viewDidLoad
{
    [super viewDidLoad];    //add the door
    CALayer *doorLayer = [CALayer layer];
    doorLayer.frame = CGRectMake(0, 0, 128, 256);
    doorLayer.position = CGPointMake(150 - 64, 150);
    doorLayer.anchorPoint = CGPointMake(0, 0.5);
    doorLayer.contents = (__bridge id)[UIImage imageNamed: @"Door.png"].CGImage;
    [self.containerView.layer addSublayer:doorLayer];    //apply perspective transform
    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = -1.0 / 500.0;
    self.containerView.layer.sublayerTransform = perspective;    //apply swinging animation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform.rotation.y";
    animation.toValue = @(-M_PI_2);
    animation.duration = 2.0;
    animation.repeatDuration = INFINITY;
    animation.autoreverses = YES;
    [doorLayer addAnimation:animation forKey:nil];
}@end

複製代碼

相關文章
相關標籤/搜索