一種動畫框架Lottie的解析(二)—— 基本介紹(二)

版本記錄

版本號 時間
V1.0 2017.09.15

前言

app中好的炫的動畫可以讓用戶耳目一新,為產品增色不少,關于動畫的實現我們可以用基本動畫、關鍵幀動畫、序列幀動畫以及基于CoreGraphic的動畫等等,接下來這幾篇我不介紹系統給的這幾種動畫繪制方法,給大家介紹的是一種動畫框架。感興趣的可以看我上面幾篇。
1. 一種動畫框架Lottie的解析(一)—— 基本介紹(一)

iOS View Controller Transitioning - iOS轉場動畫

Lottie帶有一個UIViewController動畫控制器,用于定制自定義viewController轉場動畫!

稱為轉場的代理

- (void)_showTransitionA 
{
  ToAnimationViewController *vc = [[ToAnimationViewController alloc] init];
  vc.transitioningDelegate = self;
  [self presentViewController:vc animated:YES completion:NULL];
}

LOTAnimationTransitionController中實現代理方法。

#pragma mark -- View Controller Transitioning

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source 
{
  LOTAnimationTransitionController *animationController = [[LOTAnimationTransitionController alloc] initWithAnimationNamed:@"vcTransition1" fromLayerNamed:@"outLayer" toLayerNamed:@"inLayer" applyAnimationTransform:NO];
  return animationController;
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed 
{
  LOTAnimationTransitionController *animationController = [[LOTAnimationTransitionController alloc] initWithAnimationNamed:@"vcTransition2" fromLayerNamed:@"outLayer" toLayerNamed:@"inLayer" applyAnimationTransform:NO];
  return animationController;
}

通過將applyAnimationTransform設置為YES,您可以做Lottie動畫移向和移出控制器。 它們將位于層的原點。 當設置為NO時,Lottie只需對指定的層進行遮擋,同時重新檢測z順序。


Debugging - 調試

Lottie有幾個調試功能可以了解。 當加載動畫時,不支持的功能將在控制臺中以其功能名稱打印輸出。

如果你檢查LOTHelpers.h,你會看到兩個調試標志。 ENABLE_DEBUG_LOGGINGENABLE_DEBUG_SHAPES

ENABLE_DEBUG_LOGGING增加了Lottie Logging的詳細程度。 它在動畫過程中隨時記錄動畫節點。 如果您的動畫不工作,請打開并播放動畫。 控制臺日志可能會給你一些關于發生了什么的線索。

ENABLE_DEBUG_SHAPES為每個圖層和形狀的錨點繪制一個彩色方塊。 這有助于查看屏幕上是否有任何內容。

1. keyPath

LOTAnimationView提供 - (void)logHierarchyKeypaths,它會遞歸地記錄動畫的所有可設置的關鍵字。 這有助于在運行時更改動畫。


Adding Views to an Animation at Runtime - 在運行時將視圖添加到動畫

Lautie不僅可以在運行時更改動畫,還可以在運行時將自定義UI添加到LOTAnimation。 下面的例子顯示了一些高級的用法來創建動態圖像加載器。


A Dynamic Image Loading Spinner - 一種動態圖像加載轉動動畫

上面的示例顯示了使用加載旋轉動畫設置的單個LOTAnimationView。 加載旋轉循環其動畫的一部分,而此時圖像被異步下載。 當下載完成后,將圖像添加到動畫中,其余的動畫將無縫播放。 圖像干凈地動畫化,完成塊被調用。

如果說,動畫已被設計師改變,需要更新。 所有這些都是更新捆綁包中的JSON文件。 不需要更改代碼!

在這里,設計決定為app添加“黑暗模式”。 只是幾行代碼在運行時更改動畫的顏色。

具體代碼如下所示:

import UIKit
import Lottie

class ViewController: UIViewController {
  
  var animationView: LOTAnimationView = LOTAnimationView(name: "SpinnerSpin");
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    // Setup our animaiton view
    animationView.contentMode = .scaleAspectFill
    animationView.frame = CGRect(x: 20, y: 20, width: 200, height: 200)

    self.view.addSubview(animationView)
    // Lets change some of the properties of the animation
    // We arent going to use the MaskLayer, so lets just hide it
    animationView.setValue(0, forKeypath: "MaskLayer.Ellipse 1.Transform.Opacity", atFrame: 0)
    // All of the strokes and fills are white, lets make them DarkGrey
    animationView.setValue(UIColor.darkGray, forKeypath: "OuterRing.Stroke.Color", atFrame: 0)
    animationView.setValue(UIColor.darkGray, forKeypath: "InnerRing.Stroke.Color", atFrame: 0)
    animationView.setValue(UIColor.darkGray, forKeypath: "InnerRing.Fill.Color", atFrame: 0)
    
    // Lets turn looping on, since we want it to repeat while the image is 'Downloading'
    animationView.loopAnimation = true
    // Now play from 0 to 0.5 progress and loop indefinitely.
    animationView.play(fromProgress: 0, toProgress: 0.5, withCompletion: nil)
    
    // Lets simulate a download that finishes in 4 seconds.
    let dispatchTime = DispatchTime.now() + 4.0
    DispatchQueue.main.asyncAfter(deadline: dispatchTime) {
      self.simulateImageDownloaded()
    }
  }
  
  func simulateImageDownloaded() {
    // Our downloaded image
    let image = UIImage(named: "avatar.jpg")
    let imageView = UIImageView(image: image)

    // We want the image to show up centered in the animation view at 150Px150P
    // Convert that rect to the animations coordinate space
    // The origin is set to -75, -75 because the origin is centered in the animation view
    let imageRect = animationView.convert(CGRect(x: -75, y: -75, width: 150, height: 150), toLayerNamed: nil)
    
    // Setup our image view with the rect and add rounded corners
    imageView.frame = imageRect
    imageView.layer.masksToBounds = true
    imageView.layer.cornerRadius = imageRect.width / 2;
    
    // Now we set the completion block on the currently running animation
    animationView.completionBlock = { (result: Bool) in ()
      // Add the image view to the layer named "TransformLayer"
      self.animationView.addSubview(imageView, toLayerNamed: "TransformLayer", applyTransform: true)
      // Now play the last half of the animation
      self.animationView.play(fromProgress: 0.5, toProgress: 1, withCompletion: { (complete: Bool) in
        // Now the animation has finished and our image is displayed on screen
        print("Image Downloaded and Displayed")
      })
    }
    
    // Turn looping off. Once the current loop finishes the animation will stop 
    // and the completion block will be called.
    animationView.loopAnimation = false
  }
  
}

Changing Animations At Runtime - 在運行時更改動畫

Lottie可以做的不僅僅是播放美麗的動畫。 Lottie允許您在運行時更改動畫。

下面看一下例子,包含了四個開關。

下面看實現代碼

let animationView = LOTAnimationView(name: "toggle");
self.view.addSubview(animationView)
animationView.frame.origin.x = 40
animationView.frame.origin.y = 20
animationView.autoReverseAnimation = true
animationView.loopAnimation = true
animationView.play()

let animationView2 = LOTAnimationView(name: "toggle");
self.view.addSubview(animationView2)
animationView2.frame.origin.x = 40
animationView2.frame.origin.y = animationView.frame.maxY + 4
animationView2.autoReverseAnimation = true
animationView2.loopAnimation = true
animationView2.play()

let animationView3 = LOTAnimationView(name: "toggle");
self.view.addSubview(animationView3)
animationView3.frame.origin.x = 40
animationView3.frame.origin.y = animationView2.frame.maxY + 4
animationView3.autoReverseAnimation = true
animationView3.loopAnimation = true
animationView3.play()

let animationView4 = LOTAnimationView(name: "toggle");
self.view.addSubview(animationView4)
animationView4.frame.origin.x = 40
animationView4.frame.origin.y = animationView3.frame.maxY + 4
animationView4.autoReverseAnimation = true
animationView4.loopAnimation = true
animationView4.play()

下面接著我們更改開關的顏色

下面看實現代碼

animationView2.setValue(UIColor.green, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
animationView3.setValue(UIColor.red, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
animationView4.setValue(UIColor.orange, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
[animationView2 setValue:[UIColor greenColor] forKeypath:@"BG-On.Group 1.Fill 1.Color" atFrame:@0];

keyPathAfter Effects中圖層和屬性名稱的點分隔路徑。 LOTAnimationView提供- (void)logHierarchyKeypaths,它會遞歸地記錄動畫的所有可設置的關鍵字。

現在讓我們改變一些屬性。

animationView2.setValue(UIColor.green, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
animationView2.setValue(UIColor.red, forKeypath: "BG-Off.Group 1.Fill 1.Color", atFrame: 0)

Lottie允許您更改After Effects中可動畫的任何屬性。 如果關鍵幀不存在,則為您創建一個線性關鍵幀。 如果關鍵幀確實存在,那么只是其數據被替換。


Animated Controls and Switches - 動畫控制和開關

Lottie還擁有UIControl的自定義子類,用于創建自定義的動畫交互式控件。 目前,Lottie擁有LOTAnimatedSwitch,它是一種切換式開關控制。 開關開關播放開啟或關閉動畫,并向所有目標發送UIControlStateValueChanged廣播。 與使用UISwitch的方式相同,使用幾個附加功能來設置Lottie的動畫。

您可以使用方便方法或直接提供動畫來初始化開關。

// Convenience
LOTAnimatedSwitch *toggle1 = [LOTAnimatedSwitch switchNamed:@"Switch"];
 
// Manually 
LOTComposition *comp = [LOTComposition animationNamed:@"Switch"];
LOTAnimatedSwitch *toggle1 = [[LOTAnimatedSwitch alloc] initWithFrame:CGRectZero];
[toggle1 setAnimationComp:comp];

您還可以為開機和關閉動畫指定動畫時間軸的特定部分。 默認情況下,LOTAnimatedSwitch將向前開始播放動畫,然后向后結束播放動畫。

讓我們說,提供的動畫從0.5-1開啟和從0-0.5關閉動畫。

/// On animation is 0.5 to 1 progress.
[toggle1 setProgressRangeForOnState:0.5 toProgress:1];

/// Off animation is 0 to 0.5 progress.
[toggle1 setProgressRangeForOffState:0 toProgress:0.5];

此外,所有LOTAnimatedControls都增加了狀態更改外觀更改的支持。 這需要After Effects中的一些設置。 Lottie將根據控件狀態切換可見的動畫圖層。 這可以用于具有DisabledselectedHighlighted狀態。 這些狀態與After Effects中的圖層名稱相關聯,并作為控件更改狀態動態顯示。

假設我們有一個具有Normal和Disable狀態的開關。 在效果中,我們有一個組合包含常規“按鈕”和禁用的“ Disable”狀態的Precomps。 他們有不同的視覺風格。

現在在代碼中,我們可以將UIControlState與這些層相關聯。

// Specify the layer names for different states
[statefulSwitch setLayerName:@"Button" forState:UIControlStateNormal];
[statefulSwitch setLayerName:@"Disabled" forState:UIControlStateDisabled];

// Changes visual appearance by switching animation layer to "Disabled"
statefulSwitch.enabled = NO;

// Changes visual appearance by switching animation layer to "Button"
statefulSwitch.enabled = YES;

Supported After Effects Features - 支持After Effects功能

1. Keyframe Interpolation - 關鍵幀插值

  • Linear Interpolation - 線性插值
  • Bezier Interpolation - 貝塞爾插值
  • Hold Interpolation - 保持插值
  • Rove Across Time - 漫長的時間
  • Spatial Bezier - 空間貝塞爾

2. Solids

  • Transform Anchor Point - 改變錨點
  • Transform Position - 轉變位置
  • Transform Scale - 改變尺寸
  • Transform Rotation - 改變旋轉
  • Transform Opacity - 改變不透明度

3. Masks - 遮罩

  • Path - 路徑
  • Opacity - 不透明度
  • Multiple Masks (additive, subtractive and intersection) - 多重掩模(加法,減法和交叉)

4. Track Mattes

  • Alpha Matte

5. Parenting

  • Multiple Parenting
  • Nulls

6. Shape Layers

  • Anchor Point
  • Position
  • Scale
  • Rotation
  • Opacity
  • Path
  • Group Transforms (Anchor point, position, scale etc) - 組變換(錨點,位置,尺度等)
  • Rectangle (All properties) - 矩形(所有屬性)
  • Eclipse (All properties) - 橢圓(所有屬性)
  • paths in one group - 一組中有多條路徑
  • Even-Odd winding paths - 基偶繞數路徑
  • Reverse Fill Rule - 反向填充規則

7. Stroke (shape layer)

  • Stroke Color
  • Stroke Opacity
  • Stroke Width
  • Line Cap
  • Dashes (Now Animated!)

8. Fill (shape layer)

  • Fill Color
  • Fill Opacity

9. Trim Paths (shape layer)

  • Trim Paths Start
  • Trim Paths End
  • Trim Paths Offset

10. Repeaters

  • Supports repeater transforms
  • Offset currently not supported

11. Gradients

  • Support for Linear Gradients
  • Support for Radial Gradients

12. Polystar and Polygon

  • Supported! Theres a known bug if the roundness is greater than 100 percent

13. Layer Features

  • Precomps
  • Image Layers
  • Shape Layers
  • Null Layers
  • Solid Layers
  • Parenting Layers
  • Alpha Matte Layers

14. Currently Unsupported After Effects Features

  • Merge Shapes
  • Alpha Inverted Masks
  • Trim Shapes Individually feature of Trim Paths
  • Expressions
  • 3d Layer support
  • Time remapping / Layer Reverse
  • Layer Blend Modes
  • Layer Effects

可替代方案

  • 手工制作動畫。 手工制作動畫是Android和iOS設計工程需要巨大的時間。 花費太多時間來制作動畫通常很難甚至不可能。
  • Facebook Keyframes,關鍵幀是Facebook構建的一個非常好的新庫。 然而,關鍵幀不支持一些Lottie的功能,如遮罩,修剪路徑等等。
  • GIF。Gif的體積大小是bodymovin JSON的兩倍,并且呈現為固定大小,無法按比例擴大以匹配大型和高密度屏幕。
  • Png序列。 Png序列甚至比gif更差,因為它們的文件大小通常是bodymovin json的大小的30-50倍,也不能放大。

后記

未完,待續~~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容