2014-01-06 82 views
14

我正在學習核心動畫編程指南中的動畫,並且我停留在理解圖層上的暫停和恢復動畫。理解在圖層上暫停和恢復動畫

該文件告訴我如何暫停和恢復動畫,但沒有明確的解釋。我認爲關鍵是要了解什麼是和beginTime方法CAlayer

這些代碼暫停並恢復動畫。在resumeLayer方法中,layer.beginTime = timeSincePause;這一行真的讓我感到困惑。

-(void)pauseLayer:(CALayer*)layer { 
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; 
    layer.speed = 0.0; 
    layer.timeOffset = pausedTime; 
} 

-(void)resumeLayer:(CALayer*)layer { 
    CFTimeInterval pausedTime = [layer timeOffset]; 
    layer.speed = 1.0; 
    layer.timeOffset = 0.0; 
    layer.beginTime = 0.0; 
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; 
    layer.beginTime = timeSincePause; 
} 

任何幫助將不勝感激。

+0

你是否看了CAMediaTiming協議參考? [鏈接](https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CAMediaTiming_protocol/Introduction/Introduction.html#//apple_ref/doc/uid/TP40004511-CH1-DontLinkElementID_2) – Bamsworld

+0

@Bamsworld感謝你爲鏈接。我已經看到它,但它所說的含糊不清。 – KudoCC

+0

好的,這個呢? [鏈接](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Animation_Types_Timing/Articles/Timing.html)動畫類型和定時編程指南(我認爲這是相當全面的,它解釋了時間和時間空間。) – Bamsworld

回答

6

在CAMediaTiming的報頭文件中,我們可以看到這些代碼:

/* The begin time of the object, in relation to its parent object, if 
* applicable. Defaults to 0. */ 

@property CFTimeInterval beginTime; 

/* The basic duration of the object. Defaults to 0. */ 

@property CFTimeInterval duration; 

/* The rate of the layer. Used to scale parent time to local time, e.g. 
* if rate is 2, local time progresses twice as fast as parent time. 
* Defaults to 1. */ 

@property float speed; 

/* Additional offset in active local time. i.e. to convert from parent 
* time tp to active local time t: t = (tp - begin) * speed + offset. 
* One use of this is to "pause" a layer by setting `speed' to zero and 
* `offset' to a suitable value. Defaults to 0. */ 

@property CFTimeInterval timeOffset; 

什麼重要的是下式:

T =(TP - 開始)*速度+偏移

此公式定義全球時間(或父時間,tp)如何映射到圖層的本地時間。此公式可以解釋所列代碼的所有內容:

  1. 在時間點A,動畫被暫停。設置速度= 0,timeOffset = pauseTime後,圖層的本地時間等於pauseTime。而當地時間不會再增加,因爲速度= 0;
  2. 在時間B,動畫被恢復。設置速度= 1.0,timeOffset = 0,beginTime = 0後,圖層的本地時間等於(timePause + timeSinacePause)的全局時間(或tp)。但是我們需要從時間點#A開始動畫,所以我們設置beginTime = timeSincePaused,然後圖層的本地時間等於timePause。當然,這會導致動畫從暫停點繼續。

enter image description here

+0

太好了,這就是我在等待的!我認爲當我們爲一個圖層添加一個動畫時,該圖層會保留開始和結束本地時間。隨着超級時間(tp)的增加,動畫會呈現動畫效果。 'layer.beginTime = 0.0;'用於在調用'CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime()fromLayer:nil];'in'pauseLayer'方法之前恢復圖層的本地時間相關狀態。 – KudoCC

+0

順便說一句,你用什麼工具繪製圖表? – KudoCC

+1

@KudoCC這只是Microsoft Excel :) –

0

docs

BEGINTIME

BEGINTime指定(如果適用)在關係開始接收時間到它 父對象。 (必填)

下面是從here採取它的一個很好的解釋:

如果動畫是動畫組中,BEGINTIME從 其父對象的開始偏移 - 動畫組。所以如果 beginTime的動畫是5,它會在 動畫組開始5秒後開始。

如果將動畫直接添加到圖層,則beginTime仍然是從其父對象(圖層)開始處的偏移量 。但由於 開始的一層是過去1,我不能簡單地設置 beginTime爲5來延遲動​​畫5秒,因爲5秒 開始後一層可能還是過去的時間。我通常真正想要的是相對於將動畫添加到圖層 時的延遲 - 用addTime表示。

這是從問題的代碼,並加的日誌:

- (IBAction)start:(UIButton *)sender 
{  
    [UIView animateWithDuration:10 animations:^() {//Move square to x=300 
    }completion:^(BOOL finished){}]; 
} 

- (IBAction)pause:(UIButton *)sender 
{ 
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; 
    layer.speed = 0.0; 
    layer.timeOffset = pausedTime; 
    NSLog(@"pausedTime: %f",pausedTime); 
} 

- (IBAction)resume:(UIButton *)sender 
{ 
    CFTimeInterval pausedTime = [layer timeOffset]; 
    layer.speed = 1.0; 
    layer.timeOffset = 0.0; 
    layer.beginTime = 0.0; 
    NSLog(@"CACurrentMediaTime: %f",[layer convertTime:CACurrentMediaTime() fromLayer:nil]); 
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; 
    NSLog(@"timeSincePause: %f",timeSincePause); 
    layer.beginTime = timeSincePause; 
} 

輸出:

pausedTime: 20000 
CACurrentMediaTime: 20005 
timeSincePause: 5 // <- that's your begin time. When you hit resume you want to begin the animation from that relative time. 

爲了總括起來,

的動畫持續時間總共是10個,我停下了一個imation 5和我也希望它是我的開始時間,當我恢復動畫。

因此,我保存暫停時間並從當前時間中減去它,以獲取已經過去的相對動畫時間。

+1

謝謝你的回答。但我認爲你錯過了一些重要的事情。首先,你談到的是在組動畫或添加圖層中添加的動畫的beginTime,但我想知道的是圖層的beginTime。其次,在'resume'方法中,它首先'layer.beginTime = 0.0;'然後'layer.beginTime = timeSincePause;',爲什麼不直接將layer.beginTime分配給timeSincePause。我有''layer.beginTime = 0.0;'註釋掉了,但動畫很奇怪。 – KudoCC

19

讓我們對圖層的兩個屬性進行測試:beginTimetimeOffset

前提

我們得到使用[layer convertTime:CACurrentMediaTime() fromLayer:nil]

1的CALayer的時間空間,(以前beginTime爲0),分配5.0層的beginTime

NSLog(@"CACurrentMediaTime:%f", [t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 
t1.layer.beginTime = 5.0 ; 
NSLog(@"CACurrentMediaTime:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 

結果日誌:

2014-01-15 11:00:33.811 newUserInterface[1404:70b] CACurrentMediaTime:7206.884498 
2014-01-15 11:00:33.811 newUserInterface[1404:70b] CACurrentMediaTime:7201.885088 

結果顯示,如果我在beginTime上添加5.0,圖層的時間將減去5.0。如果動畫在飛行中,則在beginTime上添加5.0將導致動畫在5.0秒前重做動畫。

2,(前timeOffset是0)指定5.0至層的timeOffset

NSLog(@"CACurrentMediaTime:%f", [t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 
t1.layer.timeOffset = 5.0 ; 
NSLog(@"CACurrentMediaTime:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 

結果是:

2014-01-15 11:09:07.757 newUserInterface[1449:70b] CACurrentMediaTime:7720.851464 
2014-01-15 11:09:07.758 newUserInterface[1449:70b] CACurrentMediaTime:7725.852011 

結果表明,如果我上timeOffset添加5.0時,層的時間將加5.0。如果動畫在飛行中,則在timeOffset上添加5.0將導致動畫跳轉到5.0秒後的動畫。

領會暫停和層

上。這裏恢復動畫是一個例子,是t1 UIViewController的根視圖的子視圖。我在t1上做了一個動畫,它動畫了t1.layer的位置。

如果將動畫添加到圖層,圖層將根據動畫的beginTime計算何時動畫動畫,如果beginTime爲0,則會立即爲其動畫。

CABasicAnimation * b1 = [CABasicAnimation animationWithKeyPath:@"position"] ; 
b1.toValue = [NSValue valueWithCGPoint:CGPointMake(160.0, 320.0)] ; 
b1.duration = 10.0f ; 
[t1.layer addAnimation:b1 forKey:@"pos"] ; 
NSLog(@"CACurrentMediaTime:%f", [t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 

日誌顯示2014-01-15 11:25:53.975 newUserInterface[1530:70b] CACurrentMediaTime:8727.108740,這意味着動畫將開始在8727和t1.layer的時間空間在8727 + 10停止。

當動畫在飛行中時,我用- (void)pauseLayer:(CALayer*)layer方法暫停動畫。

layer.speed = 0.0;將導致層站和層的時間將被設置爲0。(我知道,因爲當集layer.speed爲0,我馬上取層的時間,並記錄它)

layer.timeOffset = pausedTime;將增加pauseTime到圖層的時間(假設layer.timeOffset爲0),現在圖層的時間爲pausedTime。

- (void)pauseLayer:(CALayer *)layer 
{ 
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; // pauseTime is the time with respect to layer's time space 
    layer.speed = 0.0; // layer's local time is 0 
    layer.timeOffset = pausedTime; // layer's local time is pausedTime, so animation stop here 
} 

然後我會用- (void)resumeLayer:(CALayer*)layer方法恢復動畫。

-(void)resumeLayer:(CALayer*)layer { 
    CFTimeInterval pausedTime = [layer timeOffset]; 
    layer.speed = 1.0; 
    layer.timeOffset = 0.0; 
    layer.beginTime = 0.0; 
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; 
    layer.beginTime = timeSincePause; 
} 

如果我停止在8727 + 1動畫(表示動畫動畫爲1秒),在pauseLayer方法,layer.speed = 0將層的時間設定爲0和layer.timeOffset = pausedTime;將添加pausedTime上層的時間,因此該層的時間是pausedTime。

等一下,讓我們現在總結一下。 layer.speed爲0.0,'layer.timeOffset'等於pausedTime,它是8727 + 1,層的時間也是pausedTime。請記住,我們會盡快使用它們。

讓我們繼續,我繼續在8727 + 11動畫與resumeLayer方法,layer.speed = 1.0;它將在層的時間增加8727 + 11,所以層的時間是8727 + 1 + 8727 + 11,layer.timeOffset = 0.0;它會導致層的時間減去8727+ 1因爲layer.timeOffset之前是8727 + 1,現在層的本地時間是8727 + 11。 timeSincePause是(8727 + 11-8727-1)= 10。

layer.beginTime = timeSincePause;它導致圖層的時間減10.現在圖層的本地時間是8727 + 1,這是我暫停動畫的時間。

我會告訴你的代碼和日誌:

- (void)pauseLayer:(CALayer *)layer 
{ 
    NSLog(@"%f", CACurrentMediaTime()) ; 
    NSLog(@"pauseLayer begin:%f", [t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil] ; 
    layer.speed = 0.0 ; 
    NSLog(@"pauseLayer after set speed to 0:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 
    layer.timeOffset = pausedTime ; 
    NSLog(@"pauseLayer after set timeOffset:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 
} 

- (void)resumeLayer:(CALayer *)layer 
{ 
    NSLog(@"%f", CACurrentMediaTime()) ; 
    NSLog(@"resumeLayer begin:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 
    CFTimeInterval pausedTime = layer.timeOffset ; 
    layer.speed = 1.0 ; 
    NSLog(@"resumeLayer after set speed to 1:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 
    layer.timeOffset = 0.0; 
    NSLog(@"resumeLayer after set timeOffset to 0:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 
    layer.beginTime = 0.0 ; 
    NSLog(@"resumeLayer after set beginTime to 0:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime ; 
    layer.beginTime = timeSincePause ; 
    NSLog(@"resumeLayer after set beginTime to timeSincePause:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ; 
} 

日誌:

2014-01-15 13:14:34.157 newUserInterface[1762:70b] 15247.550325 
2014-01-15 13:14:34.158 newUserInterface[1762:70b] pauseLayer begin:15247.550826 
2014-01-15 13:14:34.158 newUserInterface[1762:70b] pauseLayer after set speed to 0:0.000000 
2014-01-15 13:14:34.159 newUserInterface[1762:70b] pauseLayer after set timeOffset:15247.551284 

2014-01-15 13:14:40.557 newUserInterface[1762:70b] 15253.950505 
2014-01-15 13:14:40.558 newUserInterface[1762:70b] resumeLayer begin:15247.551284 
2014-01-15 13:14:40.558 newUserInterface[1762:70b] resumeLayer after set speed to 1:30501.502810 
2014-01-15 13:14:40.559 newUserInterface[1762:70b] resumeLayer after set timeOffset to 0:15253.952031 
2014-01-15 13:14:40.559 newUserInterface[1762:70b] resumeLayer after set beginTime to 0:15253.952523 
2014-01-15 13:14:40.560 newUserInterface[1762:70b] resumeLayer after set beginTime to timeSincePause:15247.551294 

花葯問題在resumeLayer方法:爲什麼不兩個分配線面相結合,以一個layer.beginTime = timeSincePause;,原因是在[layer convertTime:CACurrentMediaTime() fromLayer:nil]中,結果值與layer.beginTime相關。

layer.beginTime = 0.0; 
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; 
    layer.beginTime = timeSincePause; 

說實話,我還是不知道如何動畫作品背後,有什麼我做的是分析的結果,這不是一個很好的解決方案。我很高興任何有此想法的人都可以分享。謝謝!

+0

@Unheilig不,將10分配給beginTime會導致圖層的語言環境時間減少10.順便說一句,我已經更新了我的答案,這更清晰。 – KudoCC

+0

@KudoCC你釘了它,謝謝你。 – ratsimihah

+0

@KudoCC感謝分享,我一直在爲同一主題奮鬥,我試圖在每一步採用相同的日誌記錄技術,並解決了我遇到的一些動畫問題。 –