簡體   English   中英

更新模型層時,CABasicAnimation無法正確設置動畫

[英]CABasicAnimation does not animate correctly when I update model layer

我目前正在實現一個動畫CALayer transform屬性的CABasicAnimation 現在,雖然我是Core Animation的新手,但我已經能夠收集各種博客和文章,例如objc.io,使用經常(錯誤的)推薦的方法來獲取動畫以堅持使用是非常糟糕的主意。 fillModeremovedOnCompletion屬性的動畫。 這種方法被很多人認為是不好的做法,因為它會在模型​​層和表示層之間產生差異,因此未來對其中一個層的查詢可能與用戶看到的不匹配。

相反,推薦的動畫制作方法是在將動畫添加到動畫圖層的同時更新模型圖層。 但是,我很難理解這是如何工作的。 我的動畫很簡單,就像這樣:

CATransform3D updatedTransform = [self newTransformWithCurrentTransform];
// Location 1
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
transformAnimation.duration = 1;
transformAnimation.fromValue = [NSValue valueWithCATransform3D:self.layerBeingAnimated.transform]; // Does not work without this.
transformAnimation.toValue = [NSValue valueWithCATransform3D:updatedTransform];
// Location 2
[self.layerBeingAnimated addAnimation:transformAnimation forKey:kTransformAnimationKey];
// Location 3

我已經指出了三個嘗試使用代碼更新模型層的位置

self.layerBeingAnimated.transform = updatedTransform;

在位置1中,圖層向右跳轉到newTransform並且不進行動畫處理。 在位置2中,圖層完全按照我想要的方式設置動畫,從當前變換到newTransform 在位置3中,圖層向右跳轉到newTransform ,跳回到舊變換,從fromValue到newTransform正確動畫,然后保持在newTransform

這是什么交易? 更新模型層的正確位置是什么?為什么這三個位置會產生不同的結果?

謝謝!

我認為最容易解釋三個地點中每個地點的情況,然后是最后的“結論”。

我還添加了一些插圖,准確顯示了您在問題中提到的行為,以便對於那些自己沒有嘗試過這三件事的人來說更容易理解。 我還擴展了插圖,以顯示獨立層和背襯層(一個附加到視圖),我將解釋其中有一個區別。

位置1

在第一個位置,模型值在創建動畫之前更新。 完成此操作后,transform屬性將保存updatedTransform。 這意味着當您從fromValue的圖層讀取變換時,您將獲得updatedValue。 這反過來意味着往返於值都是相同的,因此您無法看到動畫。

在此輸入圖像描述

可能使此位置按預期工作的一件事是在分配新值之前讀取oldValue,然后將其用作fromValue。 這將看起來像預期的那樣。

// Location 1
CATransform3D oldValue = layer.transform; // read the old value first
layer.transform = updatedTransform;       // then update to the new value

CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];
anim.duration  = 1.0;
anim.fromValue = [NSValue valueWithCATransform3D:oldValue];
anim.toValue   = [NSValue valueWithCATransform3D:updatedTransform];

位置2

在第二個示例中,當您讀取from值的變換時,該值尚未更新,因此fromValue和toValue不同。 之后,模型值將更新為其最終值。 這里獨立層和背襯層之間實際上存在差異,但我們沒有看到它。 CALayer上的transform屬性是可動畫的,當值發生變化時,它將自動執行“隱式”動畫。 這意味着動畫將添加到“變換”鍵路徑的圖層中。 但是,當更改發生在動畫塊之外時,視圖會禁用此行為,因此不存在隱式動畫。

我們沒有看到隱式動畫的原因是之后為相同的鍵路徑添加了“顯式”動畫。 這意味着在兩種情況下都會顯示唯一的顯式動畫,甚至認為在獨立圖層上運行了兩個動畫(稍后會詳細介紹)。 如果您感到謹慎,那么您可以禁用獨立層的隱式操作(稍后會詳細介紹)。

在此輸入圖像描述

位置3

這給我們留下了最后的位置。 在這種情況下,動畫就像上面一樣創建,具有不同的fromValue和toValue。 唯一的區別是添加顯式動畫和更改觸發隱式動畫的屬性的順序。 在這種情況下,隱式動畫在顯式動畫之后添加,它們都運行(!)。 兩個動畫實際上都是針對位置2運行的,但我們無法看到它,因為之前添加了顯式(更長)動畫。

在此輸入圖像描述

由於一切都在快速移動,我放慢了整個圖層的速度,試圖說明當兩個動畫同時運行時發生了什么。 通過這種方式,可以更容易地看到隱式動畫結束時會發生什么。 我覆蓋了表現良好的背襯層和行為不端的獨立層,使它們都是50%透明的。 虛線輪廓是原始幀。

在此輸入圖像描述

對正在發生的事情的簡短描述:藍色視圖只獲得添加到其中的顯式動畫(持續時間為1秒)。 橙色圖層首先添加了相同的顯式動畫,然后添加了隱含的0.25秒動畫。 顯式和隱式動畫都不是“加法”,意味着它們的toValue和fromValue按原樣使用。

免責聲明:我不在Apple工作,我沒有看過Core Animation的源代碼,所以我要說的是根據事情的行為進行猜測。

根據我的理解(參見免責聲明),這是每次屏幕刷新產生動畫時會發生的情況:對於當前時間戳,圖層按照添加的順序瀏覽動畫並更新演示文稿值。 在這種情況下,顯式動畫設置旋轉變換,然后隱式動畫到來並設置另一個完全覆蓋顯式變換的旋轉變換。

如果動畫配置為“添加”,它將添加到演示文稿值而不是覆蓋(這是超級強大的)。 即使使用附加動畫,訂單仍然很重要。 非加法動畫可以在以后出現並覆蓋整個事物。

由於隱式動畫比顯式動畫短,我們看到對於整個動畫的第一部分,值嚴格來自隱式動畫(最后添加)。 一旦隱式動畫結束,唯一剩下的動畫就是顯式動畫,它一直在隱式動畫下面運行。 因此,當隱式動畫結束時,顯式動畫已經進展了0.25秒,我們看到橙色層跳回到與藍色視圖相同的值,而不是跳回到開頭。

我們應該在哪里更新價值?

在這一點上,問題是,我們如何防止添加兩個動畫以及我們應該在哪里更新值? 更新值的位置不會阻止兩個動畫(但它可能會影響最終結果的外觀)。

為了防止將兩個操作添加到獨立層,我們暫時禁用所有“操作”(動畫的更通用術語):

[CATransaction begin];
[CATransaction setDisableActions:YES]; // actions are disabled for now
layer.transform = updatedTransform;
[CATransaction commit];                // until here

當我們這樣做時,只有一個動畫被添加到圖層,因此位置2或3可以工作。 這只是一個品味問題。 如果您讀取oldValue,則還可以使用位置1(只要禁用該操作)。

如果您要為后備層設置動畫,那么您不必禁用操作(視圖會為您執行此操作),但這樣做也沒有什么壞處。


在這一點上,我可以繼續討論配置動畫的其他方法,添加動畫是什么,以及為什么在這種情況下需要指定toValue和fromValue。 但我認為我已經回答了你提出的問題,而這個答案已經有點偏執了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM