Play a Lottie animation as the fill of a block, with the images and fonts that it references by URL.
A video fill plays a Lottie .json file or a dotLottie .lottie archive. The block shows the whole animation, and its layers stay out of reach. To edit the layers, load a Lottie that the importer converted into blocks.
This guide covers how to give a Lottie document a URI, how to set it as a fill, how to wait for the Lottie and its references, which references the engine loads, how to export a frame, and the errors to expect.
Creating the Scene#
The example creates a 1000 × 1000 page of 3 seconds, the length of the animation.
// A page of 3 seconds, the length of the animationval scene = engine.scene.create()val page = engine.block.create(DesignBlockType.Page)engine.block.setWidth(block = page, value = 1000F)engine.block.setHeight(block = page, value = 1000F)engine.block.appendChild(parent = scene, child = page)engine.block.setDuration(block = page, duration = 3.0)Writing a Lottie Document#
The example writes its Lottie in code, so it runs without a hosted file. The document runs for 90 frames at 30 frames per second. Its image layer fades in a photo and zooms into it. The image asset names the photo by an absolute URL.
private val lottieDocument = """ { "v": "5.7.0", "fr": 30, "ip": 0, "op": 90, "w": 1000, "h": 1000, "assets": [{ "id": "photo", "w": 2500, "h": 1667, "u": "", "p": "https://img.ly/static/ubq_samples/sample_1.jpg", "e": 0 }], "layers": [{ "ty": 2, "refId": "photo", "ip": 0, "op": 90, "st": 0, "ks": { "a": { "a": 0, "k": [1250, 833] }, "p": { "a": 0, "k": [500, 500] }, "s": { "a": 1, "k": [{ "t": 0, "s": [60, 60] }, { "t": 90, "s": [80, 80] }] }, "o": { "a": 1, "k": [{ "t": 0, "s": [0] }, { "t": 30, "s": [100] }] } } }] } """.trimIndent()Storing the Document in a Buffer#
engine.editor.createBuffer() returns a buffer:// URI, and engine.editor.setBufferData() writes the document into it. The data must be a direct ByteBuffer, which the directBytes helper of the example creates. A buffer has no directory, so a document in a buffer names its images by absolute URL. The Buffers guide explains buffers in detail.
// A buffer holds the document in memory and gives it a URIval lottieUri = engine.editor.createBuffer()engine.editor.setBufferData(uri = lottieUri, offset = 0, data = directBytes(lottieDocument))Setting the Lottie as a Fill#
engine.block.createFill(FillType.Video) creates the fill, and engine.block.setUri() sets its fill/video/fileURI property to the URI of the Lottie. For a hosted file, set its https URL the same way. engine.block.setFill() gives the fill to a graphic block.
// A video fill plays the Lottie. Set a hosted .json or .lottie URL the same way.val block = engine.block.create(DesignBlockType.Graphic)engine.block.setShape(block = block, shape = engine.block.createShape(ShapeType.Rect))engine.block.setWidth(block = block, value = 1000F)engine.block.setHeight(block = block, value = 1000F)val fill = engine.block.createFill(FillType.Video)engine.block.setUri(block = fill, property = "fill/video/fileURI", value = lottieUri)engine.block.setFill(block = block, fill = fill)engine.block.appendChild(parent = page, child = block)engine.block.setDuration(block = block, duration = 3.0)Loading the Lottie and Its References#
engine.block.forceLoadAVResource() returns when the Lottie and every image and font that it references are loaded. engine.block.getAVResourceTotalDuration() then returns the duration in seconds, the frame count divided by the frame rate.
// The load finishes when the Lottie and the images it references are loadedengine.block.forceLoadAVResource(block = fill)val duration = engine.block.getAVResourceTotalDuration(block = fill)Log.i(TAG, "Duration: $duration")Referenced Images and Fonts#
A Lottie can reference files instead of embedding them. An image asset names its file with its u directory and its p file name. A font names its file in fonts.list[].fPath. An asset with e: 1 or a data: URI is embedded and loads with the document.
A relative reference resolves against the URL of the Lottie. In https://example.com/anims/intro.json, an asset with u: 'images/' and p: 'photo.png' loads https://example.com/anims/images/photo.png.
The engine loads these references:
httpandhttpsURLsbundle://URIs- relative references that stay in the directory of the Lottie
- a
file://path in the directory of a local Lottie file
The engine refuses a path that starts with /, a .. that leaves the directory of the Lottie, a backslash and a buffer:// URI. The Lottie then draws without that image or font, and the engine logs a warning that names the reference. A reference that fails to load has the same result. The engine loads at most 256 different references of one Lottie. It draws without the others and logs a warning with their number. The export and the forced load wait for each reference before they finish. A URI resolver receives each reference after it resolves against the Lottie URL.
Exporting a Frame#
engine.block.setPlaybackTime() seeks the page to 1.5 seconds, after the fade-in. engine.block.export() exports that frame as a PNG image.
// Seek the page to 1.5 seconds and export that frameengine.block.setPlaybackTime(block = page, time = 1.5)val previewPng = engine.block.export(block = page, mimeType = MimeType.PNG)Log.i(TAG, "PNG bytes: ${previewPng.remaining()}")Handling Errors#
A file that is neither a Lottie nor a video does not load, and engine.block.forceLoadAVResource() throws an EngineException whose code is EDITOR.RESOURCE_LOAD_FAILED. The example destroys the fill and its buffer afterwards.
// A file that is not a Lottie or a video does not loadval brokenUri = engine.editor.createBuffer()engine.editor.setBufferData(uri = brokenUri, offset = 0, data = directBytes("not a Lottie"))val brokenFill = engine.block.createFill(FillType.Video)engine.block.setUri(block = brokenFill, property = "fill/video/fileURI", value = brokenUri)val errorCode = try { engine.block.forceLoadAVResource(block = brokenFill) null} catch (error: EngineException) { // EDITOR.RESOURCE_LOAD_FAILED error.code}engine.block.destroy(block = brokenFill)engine.editor.destroyBuffer(uri = brokenUri)Troubleshooting#
- An image or a font is missing: the engine logs a warning that names the reference. Check that the reference is an
http,httpsorbundle://URI, or a relative path inside the directory of the Lottie. A Lottie with more than 256 different references draws without the rest. - A document in a buffer draws without its images: a relative reference has no directory to resolve against. Name each image by an absolute URL.
- A
.lottiearchive does not load: an archive must be a valid dotLottie file within the engine limits: at most 1,024 entries, 128 MiB uncompressed and 32 MiB for the animation JSON. Otherwiseengine.block.forceLoadAVResource()throws withSCENE.LOTTIE_ARCHIVE_INVALID,SCENE.LOTTIE_ARCHIVE_TOO_MANY_ENTRIES,SCENE.LOTTIE_ARCHIVE_TOO_LARGEorSCENE.LOTTIE_ARCHIVE_UNSAFE_PATH.
API Reference#
| Method | Description |
|---|---|
editor.createBuffer() |
Create a buffer and return its URI |
editor.setBufferData(uri, offset, data) |
Write the Lottie document into the buffer |
editor.destroyBuffer(uri) |
Free a buffer |
block.createFill(FillType.Video) |
Create a video fill |
block.setUri(fill, "fill/video/fileURI", uri) |
Set the Lottie file of the fill |
block.setFill(block, fill) |
Give the block the fill |
block.forceLoadAVResource(fill) |
Load the Lottie and its references |
block.getAVResourceTotalDuration(fill) |
Read the duration of the animation in seconds |
block.setPlaybackTime(page, time) |
Seek the page |
block.export(page, mimeType) |
Export a frame |
Next Steps#
- Import Lottie Animations: load Lottie layers as editable blocks.
- Video Fills: play videos as fills.
- Buffers: store data in the engine and give it a URI.
- URI Resolver: redirect the URLs that the engine loads.