CAMediaTiming`協議(9.1 圖層時間),camediatiming9.1

來源:互聯網
上載者:User

CAMediaTiming`協議(9.1 圖層時間),camediatiming9.1

#CAMediaTiming`協議

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

持續和重複

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

這裡的一次迭代是什麼意思呢?CAMediaTiming另外還有一個屬性叫做repeatCount,代表動畫重複的迭代次數。如果duration是2,repeatCount設為3.5(三個半迭代),那麼完整的動畫時間長度將是7秒。

durationrepeatCount預設都是0。但這不意味著動畫時間長度為0秒,或者0次,這裡的0僅僅代表了“預設”,也就是0.25秒和1次,你可以用一個簡單的測試來嘗試為這兩個屬性賦多個值,如清單9.1,圖9.1展示了程式的結果。

清單9.1 測試durationrepeatCount

 1 @interface ViewController () 2  3 @property (nonatomic, weak) IBOutlet UIView *containerView; 4 @property (nonatomic, weak) IBOutlet UITextField *durationField; 5 @property (nonatomic, weak) IBOutlet UITextField *repeatField; 6 @property (nonatomic, weak) IBOutlet UIButton *startButton; 7 @property (nonatomic, strong) CALayer *shipLayer; 8  9 @end10 11 @implementation ViewController12 13 - (void)viewDidLoad14 {15     [super viewDidLoad];16     //add the ship17     self.shipLayer = [CALayer layer];18     self.shipLayer.frame = CGRectMake(0, 0, 128, 128);19     self.shipLayer.position = CGPointMake(150, 150);20     self.shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;21     [self.containerView.layer addSublayer:self.shipLayer];22 }23 24 - (void)setControlsEnabled:(BOOL)enabled25 {26     for (UIControl *control in @[self.durationField, self.repeatField, self.startButton]) {27         control.enabled = enabled;28         control.alpha = enabled? 1.0f: 0.25f;29     }30 }31 32 - (IBAction)hideKeyboard33 {34     [self.durationField resignFirstResponder];35     [self.repeatField resignFirstResponder];36 }37 38 - (IBAction)start39 {40     CFTimeInterval duration = [self.durationField.text doubleValue];41     float repeatCount = [self.repeatField.text floatValue];42     //animate the ship rotation43     CABasicAnimation *animation = [CABasicAnimation animation];44     animation.keyPath = @"transform.rotation";45     animation.duration = duration;46     animation.repeatCount = repeatCount;47     animation.byValue = @(M_PI * 2);48     animation.delegate = self;49     [self.shipLayer addAnimation:animation forKey:@"rotateAnimation"];50     //disable controls51     [self setControlsEnabled:NO];52 }53 54 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag55 {56     //reenable controls57     [self setControlsEnabled:YES];58 }59 60 @end
View Code

圖9.1 示範durationrepeatCount的測試程式

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

 

圖9.2 擺動門的動畫

對門進行擺動的代碼見清單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
View Code相對時間

每次討論到Core Animation,時間都是相對的,每個動畫都有它自己描述的時間,可以獨立地加速,延時或者位移。

beginTime指定了動畫開始之前的的延遲時間。這裡的延遲從動畫添加到可見圖層的那一刻開始測量,預設是0(就是說動畫會立刻執行)。

speed是一個時間的倍數,預設1.0,減少它會減慢圖層/動畫的時間,增加它會加快速度。如果2.0的速度,那麼對於一個duration為1的動畫,實際上在0.5秒的時候就已經完成了。

timeOffsetbeginTime類似,但是和增加beginTime導致的延遲動畫不同,增加timeOffset只是讓動畫快進到某一點,例如,對於一個持續1秒的動畫來說,設定timeOffset為0.5意味著動畫將從一半的地方開始。

beginTime不同的是,timeOffset並不受speed的影響。所以如果你把speed設為2.0,把timeOffset設定為0.5,那麼你的動畫將從動畫最後結束的地方開始,因為1秒的動畫實際上被縮短到了0.5秒。然而即使使用了timeOffset讓動畫從結束的地方開始,它仍然播放了一個完整的時間長度,這個動畫僅僅是迴圈了一圈,然後從頭開始播放。

可以用清單9.3的測試程式驗證一下,設定speedtimeOffset滑塊到隨意的值,然後點擊播放來觀察效果(見圖9.3)

清單9.3 測試timeOffsetspeed屬性

 

 1 @interface ViewController () 2  3 @property (nonatomic, weak) IBOutlet UIView *containerView; 4 @property (nonatomic, weak) IBOutlet UILabel *speedLabel; 5 @property (nonatomic, weak) IBOutlet UILabel *timeOffsetLabel; 6 @property (nonatomic, weak) IBOutlet UISlider *speedSlider; 7 @property (nonatomic, weak) IBOutlet UISlider *timeOffsetSlider; 8 @property (nonatomic, strong) UIBezierPath *bezierPath; 9 @property (nonatomic, strong) CALayer *shipLayer;10 11 @end12 13 @implementation ViewController14 15 - (void)viewDidLoad16 {17     [super viewDidLoad];18     //create a path19     self.bezierPath = [[UIBezierPath alloc] init];20     [self.bezierPath moveToPoint:CGPointMake(0, 150)];21     [self.bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];22     //draw the path using a CAShapeLayer23     CAShapeLayer *pathLayer = [CAShapeLayer layer];24     pathLayer.path = self.bezierPath.CGPath;25     pathLayer.fillColor = [UIColor clearColor].CGColor;26     pathLayer.strokeColor = [UIColor redColor].CGColor;27     pathLayer.lineWidth = 3.0f;28     [self.containerView.layer addSublayer:pathLayer];29     //add the ship30     self.shipLayer = [CALayer layer];31     self.shipLayer.frame = CGRectMake(0, 0, 64, 64);32     self.shipLayer.position = CGPointMake(0, 150);33     self.shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;34     [self.containerView.layer addSublayer:self.shipLayer];35     //set initial values36     [self updateSliders];37 }38 39 - (IBAction)updateSliders40 {41     CFTimeInterval timeOffset = self.timeOffsetSlider.value;42     self.timeOffsetLabel.text = [NSString stringWithFormat:@"%0.2f", timeOffset];43     float speed = self.speedSlider.value;44     self.speedLabel.text = [NSString stringWithFormat:@"%0.2f", speed];45 }46 47 - (IBAction)play48 {49     //create the keyframe animation50     CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];51     animation.keyPath = @"position";52     animation.timeOffset = self.timeOffsetSlider.value;53     animation.speed = self.speedSlider.value;54     animation.duration = 1.0;55     animation.path = self.bezierPath.CGPath;56     animation.rotationMode = kCAAnimationRotateAuto;57     animation.removedOnCompletion = NO;58     [self.shipLayer addAnimation:animation forKey:@"slide"];59 }60 61 @end
View Code

圖9.3 測試時間位移和速度的簡單的應用程式

fillMode

對於beginTime非0的一段動畫來說,會出現一個當動畫添加到圖層上但什麼也沒發生的狀態。類似的,removeOnCompletion被設定為NO的動畫將會在動畫結束的時候仍然保持之前的狀態。這就產生了一個問題,當動畫開始之前和動畫結束之後,被設定動畫的屬性將會是什麼值呢?

一種可能是屬性和動畫沒被添加之前保持一致,也就是在模型圖層定義的值(見第七章“隱式動畫”,模型圖層和呈現圖層的解釋)。

另一種可能是保持動畫開始之前那一幀,或者動畫結束之後的那一幀。這就是所謂的填充,因為動畫開始和結束的值用來填充開始之前和結束之後的時間。

這種行為就交給開發人員了,它可以被CAMediaTimingfillMode來控制。fillMode是一個NSString類型,可以接受如下四種常量:

kCAFillModeForwards kCAFillModeBackwards kCAFillModeBoth kCAFillModeRemoved

預設是kCAFillModeRemoved,當動畫不再播放的時候就顯示圖層模型指定的值剩下的三種類型向前,向後或者即向前又向後去填充動畫狀態,使得動畫在開始前或者結束後仍然保持開始和結束那一刻的值。

這就對避免在動畫結束的時候急速返回提供另一種方案(見第八章)。但是記住了,當用它來解決這個問題的時候,需要把removeOnCompletion設定為NO,另外需要給動畫添加一個非空的鍵,於是可以在不需要動畫的時候把它從圖層上移除。

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.