Skip to content
Permalink
Browse files

Updated Docs and broken image url (#78)

Updated the iOS, ios dynamic property docs.
  • Loading branch information...
AnanthaKrish authored and gpeal committed May 29, 2019
1 parent 59369bb commit 2d951bb1785b05a5cce596039f1d475f5cd2bbb6
Showing with 39 additions and 39 deletions.
  1. +20 −20 ios.md
  2. +19 −19 ios_dynamic_properties_tutorial.md
40 ios.md
@@ -174,14 +174,14 @@ Lottie comes with a `UIViewController` animation-controller for making custom vi

Lottie can do more than just play beautiful animations. Lottie allows you to **change** animations at runtime. Changing animations is done through Lottie's dynamic properties API. The dynamic properties API features a class for searching through animation data, `LOTKeypath`, a protocol for setting animation data `LOTValueDelegate`, several helper objects for common animation scenarios `LOTValueCallback`, `LOTBlockCallback`, `LOTInterpolatorCallback`, and finally a method for setting animation delegates on `LOTAnimationView` `setValueDelegate:forKeypath:`.

##LOTKeypath
## LOTKeypath

To understand how to change animation properties in Lottie, you should first understand how animation properties are stored in Lottie.
Animation properties are stored in a data tree that mimics the information heirarchy of After Effects. In After Effects a `Composition` is a collection of `Layers` that each have their own timelines. `Layer` objects have string names, and their contents can be an image, shape layers, fills, strokes, or just about anything that is drawable. Each object in After Effects has a name. Lottie can find these objects and properties by their name using a `LOTKeypath`. A `LOTKeypath` is an object initialized with a list of `String` names. `LOTKeypath` is used to search the backing animation data for properties and objects. Keypath string names should match the names used for layers and objects in the animation data.

Wildcards (\*) and Globstars (\*\*) can be used to search through keypaths. Wildcards will search through a single depth layer, globstars will search any depth.

###Creating a LOTKeypath
### Creating a LOTKeypath

`LOTKeypath` is initialized with either a list of strings (Objective-C only), or a single dot-seperated string.
As an example, lets say we have an animation with a layer named `Boat` and we want to target its `Position` property.
@@ -190,102 +190,102 @@ As an example, lets say we have an animation with a layer named `Boat` and we wa

We can search for it explicitly by creating a keypath that targets `Boat.Transform.Position`

####Swift
#### Swift
```swift
let keypath = LOTKeypath(string: "Boat.Transform.Position")
```
####Objective-C
#### Objective-C
```objectivec
LOTKeypath *keypath = [LOTKeypath keypathWithKeys:@"Boat", @"Transform", @"Position", nil];
// ----OR-----
LOTKeypath *keypath = [LOTKeypath keypathWithString@"Boat.Transform.Position"];
```

###Using Wildcards
### Using Wildcards

Suppose you are interested in changing the color of any shape group named `Fish` in the Animation. You can do this with Globstars, or double wild cards.

####Swift
#### Swift
```swift
let keypath = LOTKeypath(string: "**.Fish.Fill.Color")
```
####Objective-C
#### Objective-C
```objectivec
LOTKeypath *keypath = [LOTKeypath keypathWithKeys:@"**", @"Fish", @"Fill", @"Color", nil];
// ----OR-----
LOTKeypath *keypath = [LOTKeypath keypathWithString@"*.Fish.Fill.Color"];
```

##LOTValueDelegate
## LOTValueDelegate

`LOTValueDelegate` is a collection of 5 protocols used to provide new animation data for a given `LOTKeypath` search.
A value delegate is called every frame while an animation plays and requests the override data for the given property. The delegate is given the current frame of the animation, and the animation property's current data. If animation already existed for the property the delegate is given the leading and trailing keyframe as well as the current interpolated progress. Each of the 5 protocols returns a different type of animated data.

The protocols are `LOTColorValueDelegate`, `LOTNumberValueDelegate`, `LOTPointValueDelegate`, `LOTSizeValueDelegate`, `LOTPathValueDelegate`.

##Predefined LOTValueDelegate Objects
## Predefined LOTValueDelegate Objects

Lottie contains several predefined objects that conform to `LOTValueDelegate` that support a number of basic operations. There are three types of objects, `LOTValueCallback`, `LOTBlockCallback`, and `LOTInterpolatorCallback`. Each type contains an object for a specific data type. Example `LOTValueCallback` contains `LOTNumberValueCallback`, `LOTColorValueCallback`, etc.

###LOTValueCallback
### LOTValueCallback

`LOTValueCallbacks` are used to simply set a value. Each object has a property for its data type that can be set. While the animaiton is playing, Lottie will set the keypath to the value specified by the value callback. There are 5 different value callback objects: `LOTColorValueCallback`, `LOTNumberValueCallback`, `LOTPointValueCallback`, `LOTSizeValueCallback`, `LOTPathValueCallback`.

Example:
####Swift
#### Swift
```swift
let colorCallback = LOTColorValueCallback(color:UIColor.blueColor.CGColor)
```
####Objective-C
#### Objective-C
```objectivec
LOTColorValueCallback *colorCallback = [LOTColorValueCallback withCGColor:[UIColor blueColor].CGColor];
```

###LOTBlockCallback
### LOTBlockCallback

`LOTBlockCallback` is similar to valueCallback, but instead holds a block or closure that is called every frame for the property. There are 5 different block callback objects: `LOTColorBlockCallback`, `LOTNumberBlockCallback`, `LOTPointBlockCallback`, `LOTSizeBlockCallback`, `LOTPathBlockCallback`.

Example:
####Swift
#### Swift
```swift
let colorBlock = LOTColorBlockCallback { (currentFrame, startKeyFrame, endKeyFrame, interpolatedProgress, startColor, endColor, interpolatedColor) -> Unmanaged<CGColor> in
return aColor
}
```
####Objective-C
#### Objective-C
```objectivec
LOTColorBlockCallback *colorBlock = [LOTColorBlockCallback withBlock:^CGColorRef _Nonnull(CGFloat currentFrame, CGFloat startFrame, CGFloat endFrame, CGFloat interpolatedProgress, CGColorRef _Nullable startColor, CGColorRef _Nullable endColor, CGColorRef _Nullable interpolatedColor) {
return aColor;
}];
```

###LOTInterpolatorCallback
### LOTInterpolatorCallback

`LOTInterpolatorCallback` is used to interpolate between two values using a progress from 0 to 1. Each Interpolator contains a startValue, endvalue, and a currentProgress. When currentProgress is changed externally, the property is set with the interpolated value. There are 5 different interpolator callback objects: `LOTColorInterpolatorCallback`, `LOTNumberInterpolatorCallback`, `LOTPointInterpolatorCallback`, `LOTSizeInterpolatorCallback`, `LOTPathInterpolatorCallback`.

Example:
####Swift
#### Swift
```swift
let positionInterpolator = LOTPointInterpolatorCallback(from: startPoint, to: endPoint)
positionInterpolator.currentProgress = 0.5
// Sets the position to the halfway point between start and end point.
```
####Objective-C
#### Objective-C
```objectivec
LOTPointInterpolatorCallback *positionInterpolator = [LOTPointInterpolatorCallback withFromPoint:startPoint toPoint:endPoint];
positionInterpolator.currentProgress = 0.5;
// Sets the position to the halfway point between start and end point.
```

##Setting a Value Delegate
## Setting a Value Delegate

After creating a `LOTKeypath` and a `LOTValueDelegate` it is possible to set the delegate on an existing `LOTAnimationView`.

`setValueDelegate:forKeypath:` will search through the exisiting animation view, and set the `valueDelegate` on each property that matches the `keypath`. The animation will be forced to redraw. An exception will be thrown if the data type of the property does not match the data type of the delegate (Example: setting number delegate on color property).

**NOTE** `LOTAnimationView` maintains a WEAK reference to the delegate. This helps reduce retain cycles. You must maintain a reference to the delegate to keep it in memory.

##Example
## Example

Say we want to create 4 toggle switches.
![Toggle](/images/switch_Normal.gif)
@@ -25,7 +25,7 @@ Playing the animation as-is will animate the rolling waves for a second, then th

Let's start with some ground work. We need a new ViewController and a large download to track. Create a new UIViewController subclass, and import Lottie. In keeping with the maritime theme, the file we will be downloading is a 10mb oceanography map. Now lets create a network request to download our map.

####Swift:
#### Swift:
```swift
var downloadTask: URLSessionDownloadTask?
@@ -37,7 +37,7 @@ func createDownloadTask() {
downloadTask!.resume()
}
```
####Objective-C:
#### Objective-C:
```objectivec
- (void)createDownloadTask {
NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://upload.wikimedia.org/wikipedia/commons/f/ff/Pizigani_1367_Chart_10MB.jpg"]];
@@ -52,7 +52,7 @@ func createDownloadTask() {

You will also need to make your view controller class adhere to the NSURLSessionDownloadDelegate protocol and add in the following stub methods.

####Swift:
#### Swift:
```swift
class ViewController: UIViewController, URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
@@ -65,7 +65,7 @@ class ViewController: UIViewController, URLSessionDownloadDelegate {
}
```

####Objective-C:
#### Objective-C:
```objectivec
@interface LADownloadTestViewController () <NSURLSessionDownloadDelegate>
@@ -90,7 +90,7 @@ totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
## Building the UI
Now that we have our download task created, lets create the UI. We will need a single Lottie view for the animation, and a button to start the download. Add the animation's JSON [Boat_Loader.json](/AEP/Boat_Loader.zip) to the App bundle. Create the animation view, and set it to be a full-screen view.

####Swift:
#### Swift:
```swift
private var boatAnimation: LOTAnimationView?
@@ -108,7 +108,7 @@ override func viewDidLoad() {
}
```

####Objective-C
#### Objective-C
```objectivec
- (void)viewDidLoad {
[super viewDidLoad];
@@ -127,7 +127,7 @@ override func viewDidLoad() {

Now add a button placed center in the screen that will start the download. Add this to the bottom of the `viewDidLoad` function. The button will need to call a function when pressed. Add the function that the button calls that will trigger the download.

####Swift:
#### Swift:
```swift
override func viewDidLoad() {
super.viewDidLoad()
@@ -147,7 +147,7 @@ override func viewDidLoad() {
```

####Objective-C
#### Objective-C
```objectivec
- (void)viewDidLoad {
[super viewDidLoad];
@@ -165,11 +165,11 @@ override func viewDidLoad() {
}
```

##Making it all move
## Making it all move

If you run the App now you should see a boat sitting on a wave. If you click on the download button the image will download, but the animation never plays. Lets wire it all up!

![Boat_Loader_Props](Boat_Loader_Props.png)
![Boat_Loader_Props](images/Boat_Loader_Props.png)

First, let's look closer at the After Effects file. The animation has a layer named `Boat` which contains the boat and the rolling waves. We want to move this layer up the screen as the download progresses. We need to drive the position of the `Boat` layer with the progress of the download. Looking at the After Effects file we can see that the property we want to change is `Boat.Transform.Position` In order to change an animation we need two things. A `LOTKeypath` and a `LOTValueDelegate`.

@@ -184,7 +184,7 @@ Dynamic properties work in the animation's coordinate space, so we will have to

Add this at the bottom of `viewDidLoad`.

####Swift:
#### Swift:
```swift
// The center of the screen, where the boat will start
let screenCenter = CGPoint(x:view.bounds.midX, y:view.bounds.midY)
@@ -199,7 +199,7 @@ let boatEndPoint = boatAnimation!.convert(offscreenCenter, toKeypathLayer: LOTKe
positionInterpolator = LOTPointInterpolatorCallback(from: boatStartPoint, to: boatEndPoint)
```

####Objective-C
#### Objective-C
```objectivec
// The center of the screen
CGPoint screenCenter = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds));
@@ -219,7 +219,7 @@ _positionInterpolator = [LOTPointInterpolatorCallback withFromPoint:boatStartPoi

Now that we have a `_positionInterpolator` lets set it on the `Boat.Transform.Position` property of animation view and tell the animation view to loop the first half of the animation.

####Swift:
#### Swift:
```swift
// Set the interpolator on the animation view for the Boat.Transform.Position keypath.
boatAnimation!.setValueDelegate(positionInterpolator!, for:LOTKeypath(string: "Boat.Transform.Position"))
@@ -231,7 +231,7 @@ boatAnimation!.play(fromProgress: 0,
withCompletion: nil)
```

####Objective-C
#### Objective-C
```objectivec
// Set the interpolator on the animation view for the Boat.Transform.Position keypath.
[_boatLoader setValueDelegate:_positionInterpolator forKeypath:[LOTKeypath keypathWithKeys:@"Boat", @"Transform", @"Position", nil]];
@@ -243,15 +243,15 @@ _boatLoader.loopAnimation = YES;

Now, if you run the App you should see the boat moving over the waves indefinitely. If you press the download button, the boat will continue to move over the waves but nothing else happens. We need to hook the download progress up to the `_positionInterpolator` in the request's delegate callback.

####Swift:
#### Swift:
```swift
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
positionInterpolator?.currentProgress = CGFloat(totalBytesWritten) / CGFloat(totalBytesExpectedToWrite)
}
```

####Objective-C
#### Objective-C
```objectivec
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
@@ -264,7 +264,7 @@ totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {

Run the App and press download. You should see the water filling the screen as the download progresses! Fantastic! We're almost done! When the download finishes the animation should play through the current loop, then play the last half of the animation, which will notify the success of the download.

####Swift:
#### Swift:
```swift
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
// Pause the animation and disable looping.
@@ -281,7 +281,7 @@ func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, did
}
```

####Objective-C
#### Objective-C
```objectivec
- (void)URLSession:(nonnull NSURLSession *)session
downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask
@@ -301,7 +301,7 @@ didFinishDownloadingToURL:(nonnull NSURL *)location {

Run the App, and now you should see the completion animation!

##Conclusion
## Conclusion

Hopefully this has shown some of the power of dynamic properties with Lottie! This is only a small example of what can be achieved. Read the documentation on dynamic properties to see what else you can do. Happy animating!

0 comments on commit 2d951bb

Please sign in to comment.
You can’t perform that action at this time.