Lottie-ios: Support for image layers

Created on 2 Feb 2017  路  7Comments  路  Source: airbnb/lottie-ios

Thanks for making this awesome tool!

We'd love to use it, but we'd need support for image-backed layers to use our existing after effects animations. From taking a quick glance through the code, it would appear that our image layers are being ignored as they map to the LALayerTypeUnknown type. Below is the entirety of one of our simple exports with an image. Here's a link to a bodymovin image layer schema as well.

I'd be happy to take a stab at this if this is a feature you'd be interested in adding. Thanks!

{
    "assets": [{
        "id": "image_0",
        "w": 811,
        "h": 976,
        "u": "images/",
        "p": "img_0.png"
    }, {
        "id": "image_1",
        "w": 1039,
        "h": 1283,
        "u": "images/",
        "p": "img_1.png"
    }],
    "layers": [{
        "ddd": 0,
        "ind": 0,
        "ty": 2,
        "nm": "Link.png",
        "cl": "png",
        "refId": "image_0",
        "ks": {
            "o": {
                "k": 100
            },
            "r": {
                "k": [{
                    "i": {
                        "x": [0.667],
                        "y": [1]
                    },
                    "o": {
                        "x": [0.333],
                        "y": [0]
                    },
                    "n": ["0p667_1_0p333_0"],
                    "t": 60,
                    "s": [0],
                    "e": [-5]
                }, {
                    "i": {
                        "x": [0.667],
                        "y": [1]
                    },
                    "o": {
                        "x": [0.333],
                        "y": [0]
                    },
                    "n": ["0p667_1_0p333_0"],
                    "t": 65,
                    "s": [-5],
                    "e": [5]
                }, {
                    "i": {
                        "x": [0.667],
                        "y": [1]
                    },
                    "o": {
                        "x": [0.333],
                        "y": [0]
                    },
                    "n": ["0p667_1_0p333_0"],
                    "t": 70,
                    "s": [5],
                    "e": [-5]
                }, {
                    "i": {
                        "x": [0.667],
                        "y": [1]
                    },
                    "o": {
                        "x": [0.333],
                        "y": [0]
                    },
                    "n": ["0p667_1_0p333_0"],
                    "t": 75,
                    "s": [-5],
                    "e": [5]
                }, {
                    "i": {
                        "x": [0.667],
                        "y": [1]
                    },
                    "o": {
                        "x": [0.333],
                        "y": [0]
                    },
                    "n": ["0p667_1_0p333_0"],
                    "t": 80,
                    "s": [5],
                    "e": [0]
                }, {
                    "t": 85
                }]
            },
            "p": {
                "k": [1308, 572, 0]
            },
            "a": {
                "k": [405.5, 488, 0]
            },
            "s": {
                "k": [75, 75, 100]
            }
        },
        "ao": 0,
        "ip": 0,
        "op": 252,
        "st": 0,
        "bm": 0,
        "sr": 1
    }, {
        "ddd": 0,
        "ind": 1,
        "ty": 2,
        "nm": "keys.png",
        "cl": "png",
        "refId": "image_1",
        "ks": {
            "o": {
                "k": 100
            },
            "r": {
                "k": [{
                    "i": {
                        "x": [0.667],
                        "y": [1]
                    },
                    "o": {
                        "x": [0.333],
                        "y": [0]
                    },
                    "n": ["0p667_1_0p333_0"],
                    "t": 0,
                    "s": [0],
                    "e": [-2]
                }, {
                    "i": {
                        "x": [0.667],
                        "y": [1]
                    },
                    "o": {
                        "x": [0.333],
                        "y": [0]
                    },
                    "n": ["0p667_1_0p333_0"],
                    "t": 5,
                    "s": [-2],
                    "e": [2]
                }, {
                    "i": {
                        "x": [0.667],
                        "y": [1]
                    },
                    "o": {
                        "x": [0.333],
                        "y": [0]
                    },
                    "n": ["0p667_1_0p333_0"],
                    "t": 10,
                    "s": [2],
                    "e": [-2]
                }, {
                    "i": {
                        "x": [0.667],
                        "y": [1]
                    },
                    "o": {
                        "x": [0.333],
                        "y": [0]
                    },
                    "n": ["0p667_1_0p333_0"],
                    "t": 15,
                    "s": [-2],
                    "e": [2]
                }, {
                    "i": {
                        "x": [0.667],
                        "y": [1]
                    },
                    "o": {
                        "x": [0.333],
                        "y": [0]
                    },
                    "n": ["0p667_1_0p333_0"],
                    "t": 20,
                    "s": [2],
                    "e": [0]
                }, {
                    "t": 25
                }]
            },
            "p": {
                "k": [580, 524, 0]
            },
            "a": {
                "k": [287.5, 641.5, 0]
            },
            "s": {
                "k": [75, 75, 100]
            }
        },
        "ao": 0,
        "ip": 0,
        "op": 251,
        "st": 0,
        "bm": 0,
        "sr": 1
    }, {
        "ddd": 0,
        "ind": 2,
        "ty": 1,
        "nm": "Yellow Solid 1",
        "ks": {
            "o": {
                "k": 100
            },
            "r": {
                "k": 0
            },
            "p": {
                "k": [960, 540, 0]
            },
            "a": {
                "k": [960, 540, 0]
            },
            "s": {
                "k": [100, 100, 100]
            }
        },
        "ao": 0,
        "sw": 1920,
        "sh": 1080,
        "sc": "#ffc400",
        "ip": 0,
        "op": 263,
        "st": 0,
        "bm": 0,
        "sr": 1
    }],
    "v": "4.5.3",
    "ddd": 0,
    "ip": 0,
    "op": 240,
    "fr": 60,
    "w": 1920,
    "h": 1080
}
enhancement

Most helpful comment

Added!

All 7 comments

We definitely have images on our roadmap too. The actual implementation seems pretty straight forward. The only thing we hadn't thought through yet was how to handle the more logistical problem of loading the images.
They would have to be bundled into the app with the json, for file path reasons. Animations loaded from URL wouldn't support images unless we included a way to download those images from the json, which would mean the json would have to be point to the image URL location. Hmmmm.

Just a thought along these lines as we have been exploring this all day. First, this is fantastic, thank you for all the work!!! Really great job.

It looks like in a couple of weeks bodymovin adding support for animation only exports

https://github.com/bodymovin/bodymovin/issues/239

It would potentially solve the image loading issue or point a way possibly if you could just attach the animation to whatever target you wanted. Then the user could load their image however they needed and apply the animation on top.

To be sure, maybe 90% of the time, the contents of the shape layer is what we want on screen, but there are other times where the shape layer is simply a placeholder and we want the animation on it just applied to something else.

@aventurella Thanks for the suggestion. A little bit of a clarification on our side however: the images themselves are part of the animation, so discarding them entirely wouldn't solve this specific issue.

Sounds like a good solution for animations with static background images, for example.

@aventurella Hey! So Lottie currently supports masking UI elements with layers from after effects.
The method - (void)addSubview:(UIView *)view toLayerNamed:(NSString *)layer; will take the UIView and perform a clipping mask with the specified after effects layer. Currently it will only mask the layer but we plan to flush this feature out a bit more very soon to include parenting.

ah! Ya that would do the trick. You know I saw that in the docks and it didn't occur to me immediately. I was thinking of something else at the time. Hahahah thanks for bringing it back up!

Added!

Running on the device(iOS 10.2) seems to have a problem锛宨mages not display锛宐ut it's fine on simulator. @buba447

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zhangjunmax picture zhangjunmax  路  3Comments

albertoNovo picture albertoNovo  路  3Comments

amannayak0007 picture amannayak0007  路  3Comments

JALsnipe picture JALsnipe  路  4Comments

CentrumGuy picture CentrumGuy  路  4Comments