版本記錄
版本號 | 時間 |
---|---|
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_LOGGING
和ENABLE_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];
keyPath
是After 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將根據控件狀態切換可見的動畫圖層。 這可以用于具有Disabled
,selected
或Highlighted
狀態。 這些狀態與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
倍,也不能放大。
后記
未完,待續~~