2014-03-12 86 views
9

我最近發現了一些UIView動畫代碼,並注意到它沒有正確使用animateKeyframesWithDuration:delay:options:animations:completion:方法,並且一直試圖修復它,但由於某些原因,動畫並不相同。UIView animateKeyframesWithDuration vs標準動畫塊動畫不同

下面是我找到的代碼:

view.transform = CGAffineTransformMakeTranslation(300, 0); 

[UIView animateKeyframesWithDuration:duration/4 delay:delay options:0 animations:^{ 
    // End 
    view.transform = CGAffineTransformMakeTranslation(-10, 0); 
} completion:^(BOOL finished) { 
    [UIView animateKeyframesWithDuration:duration/4 delay:0 options:0 animations:^{ 
     // End 
     view.transform = CGAffineTransformMakeTranslation(5, 0); 
    } completion:^(BOOL finished) { 
     [UIView animateKeyframesWithDuration:duration/4 delay:0 options:0 animations:^{ 
      // End 
      view.transform = CGAffineTransformMakeTranslation(-2, 0); 
     } completion:^(BOOL finished) { 
      [UIView animateKeyframesWithDuration:duration/4 delay:0 options:0 animations:^{ 
       // End 
       view.transform = CGAffineTransformMakeTranslation(0, 0); 
      } completion:^(BOOL finished) { 
      }]; 
     }]; 
    }]; 
}]; 

有兩個問題:

  1. 每個人都應該真正使用關鍵幀動畫,而不是結束塊內嵌套的動畫。
  2. 使用animateKeyframesWithDuration:delay:options:animations:completion:時,應該調用動畫塊內的addKeyframeWithRelativeStartTime:relativeDuration:animations:方法。如果你不調用這個方法,那麼這個方法的行爲就像一個標準的UIView動畫塊。

See Apple's documentation regarding this method here.

所以,我想通過正確使用此方法來解決這個問題:

view.transform = CGAffineTransformMakeTranslation(300, 0); 
double frameDuration = 1.0/4.0; // 4 = number of keyframes 

[UIView animateKeyframesWithDuration:duration delay:delay options:0 animations:^{ 
    [UIView addKeyframeWithRelativeStartTime:0*frameDuration relativeDuration:frameDuration animations:^{ 
     view.transform = CGAffineTransformMakeTranslation(-10, 0); 
    }]; 
    [UIView addKeyframeWithRelativeStartTime:1*frameDuration relativeDuration:frameDuration animations:^{ 
     view.transform = CGAffineTransformMakeTranslation(5, 0); 
    }]; 
    [UIView addKeyframeWithRelativeStartTime:2*frameDuration relativeDuration:frameDuration animations:^{ 
     view.transform = CGAffineTransformMakeTranslation(-2, 0); 
    }]; 
    [UIView addKeyframeWithRelativeStartTime:3*frameDuration relativeDuration:frameDuration animations:^{ 
     view.transform = CGAffineTransformMakeTranslation(0, 0); 
    }]; 
} completion:nil]; 

我覺得這兩個動畫應該是相同的,但是他們沒有。我在做什麼錯了?

編輯:Example project(使用命令+ T切換在模擬器慢動畫)

+0

「但是,它們不是。」你能詳細說明嗎?他們有什麼不同? –

+0

對不起,我真的應該添加一個我現在添加的示例項目。關鍵幀的時間點不匹配。另外:哇,大衛Rönnqvist!你的[Clear * Animation Code post](http://ronnqvi.st/clear-animation-code/)是我發佈這個問題的原因! – iMaddin

回答

17

TL;博士:他們可能會有所不同,因爲他們做不同的事情,導致被添加到兩種觀點不同的動畫。不幸的是我不知道如何解決它。

發生了什麼事的第一個版本

背後正如你已經說的第一個版本不正確使用API​​。它不會使用addKeyframeWithRelativeStartTime:relativeDuration:animations:添加關鍵幀,而是直接在動畫塊內更改屬性。然後它會在完成塊中創建一個新的「關鍵幀動畫」(你很快就會明白爲什麼我會使用恐嚇報價)。

在幕後這實際上並不導致CAKeyframeAnimations(儘管我不認爲你應該依賴這個事實)。這是一些日誌記錄,我將這四個動畫對象添加到項目中view1後面的圖層中。 (我欺騙了一下,只記錄了變換的.m41部分(對應於x的平移))。

BASIC 
keyPath: transform 
duration: 0.125 
from: 300.0 
model value: -10.0 
timing: easeInEaseOut 

BASIC 
keyPath: transform 
duration: 0.125 
from: -10.0 
model value: 5.0 
timing: easeInEaseOut 

BASIC 
keyPath: transform 
duration: 0.125 
from: 5.0 
model value: -2.0 
timing: easeInEaseOut 

BASIC 
keyPath: transform 
duration: 0.125 
from: -2.0 
model value: 0.0 
timing: easeInEaseOut 

正如你可以看到每個動畫具有fromValue但既不toValuebyValue。正如你可以在文件中閱讀,這意味着:

fromValue是非nil。插值在fromValue和該屬性的當前表示值之間。


發生了什麼事的第二個版本

在另一方面的背後,是正確添加關鍵幀在這個單一CAKeyframeAnimation動畫效果的第二個版本將被添加到後面view2層。 (我還只有登錄的改造.m41部分)

KEYFRAME 
keyPath: transform 
duration: 0.500 
values: (
    300, 
    -10, 
    5, 
    -2, 
    0 
) 
keyTimes: (
    0.0, 
    0.25, 
    0.5, 
    0.75, 
    1.0 
) 
timing: easeInEaseOut 
timings: (nil) 
calculationMode: linear 

正如你可以看到它使用相同的時間相同的值之間,但在一個動畫關鍵幀動畫。它也具有相同的總持續時間並使用相同的定時功能。

有一件事我不理解。如果我修改了真正的關鍵幀動畫(在調用super之前被重寫的addAnimation:forKey:的內部)來顯式設置定時函數陣列中的定時函數,那麼它們看起來完全一樣。也就是說,我在關鍵幀動畫添加到圖層之前對其進行了處理。

CAMediaTimingFunction *function = keyFrame.timingFunction; 
keyFrame.timingFunction = nil; 
keyFrame.timingFunctions = @[function, function, function, function]; 

這招超級難看,你不應該使用它不是純粹的調試其他的東西!


那麼,爲什麼他們看起來有什麼不同?

嗯,我想答案與UIKit在第二種情況下創建的關鍵幀動畫的時序函數數組有關。這幾乎是我得到的唯一結論。

這就是說,我不知道這是一個錯誤還是如何解決它。我只知道你的項目中的代碼實際上在Core Animation級別上做了什麼。

+3

UIKit實際上將'timingFunctions'留空。它設置'timingFunction',就是這樣。 UIKit沒有API(截至iOS 9)。現在,我創建了這個小擴展,它允許在事實之後調整'timingFunction'和'timingFunctions':https://github.com/salutis/View-KeyframeAnimationCurve –

+0

您是如何記錄這些動畫描述的?我需要調試我的動畫並想獲得類似的輸出。 – GRiMe2D