0
# Dynamic Properties
1
2
Runtime animation modification system using keypaths to target specific elements and properties. This powerful system allows you to dynamically change colors, positions, transforms, and other animation properties without modifying the source animation files.
3
4
## Capabilities
5
6
### KeyPath Targeting
7
8
KeyPath system for targeting specific animation elements using hierarchical paths with support for wildcards and globstars.
9
10
```java { .api }
11
/**
12
* Keypath for targeting specific animation elements
13
*/
14
public class KeyPath {
15
// Constructors
16
public KeyPath(String... keys);
17
18
// Static instances
19
public static final KeyPath COMPOSITION; // Targets root composition
20
21
// Path manipulation (internal)
22
@RestrictTo(RestrictTo.Scope.LIBRARY)
23
public KeyPath addKey(String key);
24
@RestrictTo(RestrictTo.Scope.LIBRARY)
25
public KeyPath resolve(KeyPathElement element);
26
@RestrictTo(RestrictTo.Scope.LIBRARY)
27
public KeyPathElement getResolvedElement();
28
29
// Path matching (internal)
30
@RestrictTo(RestrictTo.Scope.LIBRARY)
31
public boolean matches(String key, int depth);
32
@RestrictTo(RestrictTo.Scope.LIBRARY)
33
public int incrementDepthBy(String key, int depth);
34
@RestrictTo(RestrictTo.Scope.LIBRARY)
35
public boolean fullyResolvesTo(String key, int depth);
36
@RestrictTo(RestrictTo.Scope.LIBRARY)
37
public boolean propagateToChildren(String key, int depth);
38
39
// Utility methods
40
public String keysToString();
41
42
@Override
43
public boolean equals(Object o);
44
@Override
45
public int hashCode();
46
@Override
47
public String toString();
48
}
49
```
50
51
**KeyPath Patterns:**
52
53
- **Exact match**: `new KeyPath("Layer Name", "Shape Group", "Fill")`
54
- **Wildcard** (`*`): Matches exactly one element - `new KeyPath("*", "Shape Group", "Fill")`
55
- **Globstar** (`**`): Matches zero or more elements - `new KeyPath("**", "Fill")`
56
- **Root composition**: `KeyPath.COMPOSITION` - targets the entire animation
57
58
**Usage Examples:**
59
60
```java
61
// Target specific layer's fill color
62
KeyPath colorPath = new KeyPath("Character", "Body", "Fill 1");
63
animationView.addValueCallback(colorPath, LottieProperty.COLOR,
64
new LottieValueCallback<>(Color.BLUE));
65
66
// Target all fills in animation
67
KeyPath allFills = new KeyPath("**", "Fill");
68
animationView.addValueCallback(allFills, LottieProperty.COLOR,
69
new LottieValueCallback<>(Color.GREEN));
70
71
// Target specific layer with wildcard
72
KeyPath layerPath = new KeyPath("Layer *", "Transform");
73
animationView.addValueCallback(layerPath, LottieProperty.TRANSFORM_OPACITY,
74
new LottieValueCallback<>(50)); // 50% opacity
75
76
// Target root composition transform
77
animationView.addValueCallback(KeyPath.COMPOSITION, LottieProperty.TRANSFORM_SCALE,
78
new LottieValueCallback<>(new ScaleXY(2.0f, 2.0f)));
79
80
// Resolve keypath to see what elements match
81
List<KeyPath> resolvedPaths = animationView.resolveKeyPath(new KeyPath("**", "Fill"));
82
for (KeyPath path : resolvedPaths) {
83
Log.d("Lottie", "Resolved path: " + path.keysToString());
84
}
85
```
86
87
### LottieProperty Constants
88
89
Constants defining all animatable properties that can be modified through dynamic property callbacks.
90
91
```java { .api }
92
/**
93
* Constants for animatable properties
94
*/
95
public interface LottieProperty {
96
// Color properties (ColorInt values)
97
Integer COLOR = 1;
98
Integer STROKE_COLOR = 2;
99
Integer DROP_SHADOW_COLOR = 5;
100
101
// Opacity properties (0-100 to match After Effects)
102
Integer TRANSFORM_OPACITY = 3;
103
Integer OPACITY = 4; // [0,100]
104
Float DROP_SHADOW_OPACITY = 15f; // [0,100]
105
Float TRANSFORM_START_OPACITY = 12f; // [0,100]
106
Float TRANSFORM_END_OPACITY = 12.1f; // [0,100]
107
108
// Transform properties
109
PointF TRANSFORM_ANCHOR_POINT = new PointF(); // In Px
110
PointF TRANSFORM_POSITION = new PointF(); // In Px
111
Float TRANSFORM_POSITION_X = 15f; // In Px (when split dimensions enabled)
112
Float TRANSFORM_POSITION_Y = 16f; // In Px (when split dimensions enabled)
113
ScaleXY TRANSFORM_SCALE = new ScaleXY();
114
Float TRANSFORM_ROTATION = 1f; // In degrees
115
Float TRANSFORM_SKEW = 0f; // 0-85
116
Float TRANSFORM_SKEW_ANGLE = 0f; // In degrees
117
118
// Shape properties
119
PointF ELLIPSE_SIZE = new PointF(); // In Px
120
PointF RECTANGLE_SIZE = new PointF(); // In Px
121
Float CORNER_RADIUS = 0f; // In degrees
122
PointF POSITION = new PointF(); // In Px
123
124
// Stroke properties
125
Float STROKE_WIDTH = 2f; // In Px
126
127
// Polystar properties
128
Float POLYSTAR_POINTS = 6f;
129
Float POLYSTAR_ROTATION = 7f; // In degrees
130
Float POLYSTAR_INNER_RADIUS = 8f; // In Px
131
Float POLYSTAR_OUTER_RADIUS = 9f; // In Px
132
Float POLYSTAR_INNER_ROUNDEDNESS = 10f; // [0,100]
133
Float POLYSTAR_OUTER_ROUNDEDNESS = 11f; // [0,100]
134
135
// Repeater properties
136
Float REPEATER_COPIES = 4f;
137
Float REPEATER_OFFSET = 5f;
138
139
// Text properties
140
Float TEXT_TRACKING = 3f;
141
Float TEXT_SIZE = 14f; // In Dp
142
Typeface TYPEFACE = Typeface.DEFAULT;
143
CharSequence TEXT = "dynamic_text";
144
145
// Time properties
146
Float TIME_REMAP = 13f; // Time value in seconds
147
148
// Effect properties
149
Float BLUR_RADIUS = 17f; // In Px
150
ColorFilter COLOR_FILTER = new ColorFilter();
151
152
// Drop shadow properties (resolved on drawing content)
153
Float DROP_SHADOW_DIRECTION = 16f; // Degrees from 12 o'clock
154
Float DROP_SHADOW_DISTANCE = 17f; // In Px
155
Float DROP_SHADOW_RADIUS = 18f; // In Px
156
157
// Gradient properties
158
Integer[] GRADIENT_COLOR = new Integer[0]; // Array of ARGB colors
159
160
// Image properties
161
Bitmap IMAGE = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
162
}
163
```
164
165
**Usage Examples:**
166
167
```java
168
// Change fill color
169
animationView.addValueCallback(
170
new KeyPath("Layer", "Shape", "Fill"),
171
LottieProperty.COLOR,
172
new LottieValueCallback<>(Color.parseColor("#FF5722"))
173
);
174
175
// Modify transform properties
176
animationView.addValueCallback(
177
new KeyPath("MovingObject"),
178
LottieProperty.TRANSFORM_POSITION,
179
new LottieValueCallback<>(new PointF(100, 200))
180
);
181
182
// Adjust opacity
183
animationView.addValueCallback(
184
new KeyPath("FadingLayer"),
185
LottieProperty.TRANSFORM_OPACITY,
186
new LottieValueCallback<>(75) // 75% opacity
187
);
188
189
// Scale animation
190
animationView.addValueCallback(
191
KeyPath.COMPOSITION,
192
LottieProperty.TRANSFORM_SCALE,
193
new LottieValueCallback<>(new ScaleXY(1.5f, 1.5f))
194
);
195
196
// Change stroke width
197
animationView.addValueCallback(
198
new KeyPath("**", "Stroke"),
199
LottieProperty.STROKE_WIDTH,
200
new LottieValueCallback<>(8.0f) // 8px stroke
201
);
202
203
// Dynamic text replacement
204
animationView.addValueCallback(
205
new KeyPath("TextLayer"),
206
LottieProperty.TEXT,
207
new LottieValueCallback<>("New Dynamic Text")
208
);
209
210
// Apply color filter to entire animation
211
animationView.addValueCallback(
212
KeyPath.COMPOSITION,
213
LottieProperty.COLOR_FILTER,
214
new LottieValueCallback<>(new PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.SRC_ATOP))
215
);
216
217
// Replace image asset
218
animationView.addValueCallback(
219
new KeyPath("ImageLayer"),
220
LottieProperty.IMAGE,
221
new LottieValueCallback<>(customBitmap)
222
);
223
```
224
225
### LottieValueCallback System
226
227
Base callback system for providing dynamic values to animation properties. Supports both static values and frame-by-frame dynamic values.
228
229
```java { .api }
230
/**
231
* Base class for dynamic property callbacks
232
*/
233
public class LottieValueCallback<T> {
234
// Constructors
235
public LottieValueCallback();
236
public LottieValueCallback(T staticValue);
237
238
// Value provision
239
public T getValue(LottieFrameInfo<T> frameInfo);
240
public final void setValue(T value);
241
242
// Internal animation binding
243
@RestrictTo(RestrictTo.Scope.LIBRARY)
244
public final T getValueInternal(
245
float startFrame,
246
float endFrame,
247
T startValue,
248
T endValue,
249
float linearKeyframeProgress,
250
float interpolatedKeyframeProgress,
251
float overallProgress);
252
@RestrictTo(RestrictTo.Scope.LIBRARY)
253
public final void setAnimation(BaseKeyframeAnimation<?, ?> animation);
254
}
255
256
/**
257
* Frame information provided to value callbacks
258
*/
259
public class LottieFrameInfo<T> {
260
// Frame timing
261
public float getStartFrame();
262
public float getEndFrame();
263
264
// Keyframe values
265
public T getStartValue();
266
public T getEndValue();
267
268
// Progress information
269
public float getLinearKeyframeProgress(); // Linear progress 0-1
270
public float getInterpolatedKeyframeProgress(); // Eased progress 0-1
271
public float getOverallProgress(); // Overall animation progress 0-1
272
273
// Internal state management
274
@RestrictTo(RestrictTo.Scope.LIBRARY)
275
public LottieFrameInfo<T> set(
276
float startFrame, float endFrame,
277
T startValue, T endValue,
278
float linearKeyframeProgress,
279
float interpolatedKeyframeProgress,
280
float overallProgress);
281
}
282
```
283
284
**Usage Examples:**
285
286
```java
287
// Static value callback
288
animationView.addValueCallback(
289
new KeyPath("Layer"),
290
LottieProperty.COLOR,
291
new LottieValueCallback<>(Color.RED) // Always red
292
);
293
294
// Dynamic value callback
295
animationView.addValueCallback(
296
new KeyPath("PulsingCircle"),
297
LottieProperty.TRANSFORM_SCALE,
298
new LottieValueCallback<ScaleXY>() {
299
@Override
300
public ScaleXY getValue(LottieFrameInfo<ScaleXY> frameInfo) {
301
// Pulse between 0.8x and 1.2x based on progress
302
float progress = frameInfo.getOverallProgress();
303
float scale = 1.0f + 0.2f * (float) Math.sin(progress * Math.PI * 4);
304
return new ScaleXY(scale, scale);
305
}
306
}
307
);
308
309
// Color interpolation based on progress
310
animationView.addValueCallback(
311
new KeyPath("ColorChangingShape"),
312
LottieProperty.COLOR,
313
new LottieValueCallback<Integer>() {
314
@Override
315
public Integer getValue(LottieFrameInfo<Integer> frameInfo) {
316
float progress = frameInfo.getOverallProgress();
317
// Interpolate from red to blue
318
int red = (int) (255 * (1 - progress));
319
int blue = (int) (255 * progress);
320
return Color.rgb(red, 0, blue);
321
}
322
}
323
);
324
325
// Position animation following circular path
326
animationView.addValueCallback(
327
new KeyPath("CircularMotion"),
328
LottieProperty.TRANSFORM_POSITION,
329
new LottieValueCallback<PointF>() {
330
@Override
331
public PointF getValue(LottieFrameInfo<PointF> frameInfo) {
332
float progress = frameInfo.getOverallProgress();
333
float angle = progress * 2 * (float) Math.PI;
334
float radius = 100f;
335
float centerX = 200f;
336
float centerY = 200f;
337
338
return new PointF(
339
centerX + radius * (float) Math.cos(angle),
340
centerY + radius * (float) Math.sin(angle)
341
);
342
}
343
}
344
);
345
346
// Using keyframe interpolation values
347
animationView.addValueCallback(
348
new KeyPath("BlendingShape"),
349
LottieProperty.COLOR,
350
new LottieValueCallback<Integer>() {
351
@Override
352
public Integer getValue(LottieFrameInfo<Integer> frameInfo) {
353
// Use original keyframe values with custom blending
354
Integer startColor = frameInfo.getStartValue();
355
Integer endColor = frameInfo.getEndValue();
356
float interpolatedProgress = frameInfo.getInterpolatedKeyframeProgress();
357
358
if (startColor == null || endColor == null) {
359
return Color.WHITE; // Fallback
360
}
361
362
// Custom color interpolation
363
return interpolateColor(startColor, endColor, interpolatedProgress);
364
}
365
366
private Integer interpolateColor(Integer startColor, Integer endColor, float progress) {
367
int startRed = Color.red(startColor);
368
int startGreen = Color.green(startColor);
369
int startBlue = Color.blue(startColor);
370
371
int endRed = Color.red(endColor);
372
int endGreen = Color.green(endColor);
373
int endBlue = Color.blue(endColor);
374
375
int red = (int) (startRed + (endRed - startRed) * progress);
376
int green = (int) (startGreen + (endGreen - startGreen) * progress);
377
int blue = (int) (startBlue + (endBlue - startBlue) * progress);
378
379
return Color.rgb(red, green, blue);
380
}
381
}
382
);
383
384
// Update static value dynamically
385
LottieValueCallback<Integer> colorCallback = new LottieValueCallback<>(Color.RED);
386
animationView.addValueCallback(path, LottieProperty.COLOR, colorCallback);
387
388
// Later, change the static value
389
colorCallback.setValue(Color.BLUE); // Animation will update automatically
390
```
391
392
### Specialized Value Callbacks
393
394
Pre-built callback implementations for common use cases involving relative values and interpolation.
395
396
```java { .api }
397
/**
398
* Simple static value callback
399
*/
400
public class SimpleLottieValueCallback<T> extends LottieValueCallback<T> {
401
public SimpleLottieValueCallback(T value);
402
}
403
404
/**
405
* Relative float value callback
406
*/
407
public class LottieRelativeFloatValueCallback extends LottieValueCallback<Float> {
408
public LottieRelativeFloatValueCallback();
409
public LottieRelativeFloatValueCallback(Float staticValue);
410
public Float getOffset(LottieFrameInfo<Float> frameInfo);
411
}
412
413
/**
414
* Relative integer value callback
415
*/
416
public class LottieRelativeIntegerValueCallback extends LottieValueCallback<Integer> {
417
public LottieRelativeIntegerValueCallback();
418
public LottieRelativeIntegerValueCallback(Integer staticValue);
419
public Integer getOffset(LottieFrameInfo<Integer> frameInfo);
420
}
421
422
/**
423
* Relative point value callback
424
*/
425
public class LottieRelativePointValueCallback extends LottieValueCallback<PointF> {
426
public LottieRelativePointValueCallback();
427
public LottieRelativePointValueCallback(PointF staticValue);
428
public PointF getOffset(LottieFrameInfo<PointF> frameInfo);
429
}
430
431
/**
432
* Interpolated float value
433
*/
434
public class LottieInterpolatedFloatValue extends LottieValueCallback<Float> {
435
public LottieInterpolatedFloatValue(Float startValue, Float endValue);
436
public LottieInterpolatedFloatValue(Float startValue, Float endValue, Interpolator interpolator);
437
}
438
439
/**
440
* Interpolated integer value
441
*/
442
public class LottieInterpolatedIntegerValue extends LottieValueCallback<Integer> {
443
public LottieInterpolatedIntegerValue(Integer startValue, Integer endValue);
444
public LottieInterpolatedIntegerValue(Integer startValue, Integer endValue, Interpolator interpolator);
445
}
446
447
/**
448
* Interpolated point value
449
*/
450
public class LottieInterpolatedPointValue extends LottieValueCallback<PointF> {
451
public LottieInterpolatedPointValue(PointF startValue, PointF endValue);
452
public LottieInterpolatedPointValue(PointF startValue, PointF endValue, Interpolator interpolator);
453
}
454
```
455
456
**Usage Examples:**
457
458
```java
459
// Simple static callback
460
animationView.addValueCallback(
461
path,
462
LottieProperty.COLOR,
463
new SimpleLottieValueCallback<>(Color.MAGENTA)
464
);
465
466
// Relative offset - adds to original animation values
467
animationView.addValueCallback(
468
new KeyPath("MovingObject"),
469
LottieProperty.TRANSFORM_POSITION,
470
new LottieRelativePointValueCallback(new PointF(50, 100)) // Offset by 50,100
471
);
472
473
// Interpolated values with custom interpolation
474
animationView.addValueCallback(
475
new KeyPath("FadingElement"),
476
LottieProperty.TRANSFORM_OPACITY,
477
new LottieInterpolatedFloatValue(
478
100f, 0f, // From 100% to 0% opacity
479
new AccelerateDecelerateInterpolator()
480
)
481
);
482
483
// Dynamic relative positioning
484
animationView.addValueCallback(
485
new KeyPath("FollowingElement"),
486
LottieProperty.TRANSFORM_POSITION,
487
new LottieRelativePointValueCallback() {
488
@Override
489
public PointF getOffset(LottieFrameInfo<PointF> frameInfo) {
490
// Dynamic offset based on animation progress
491
float progress = frameInfo.getOverallProgress();
492
return new PointF(progress * 200f, (float) Math.sin(progress * Math.PI) * 50f);
493
}
494
}
495
);
496
```
497
498
## Utility Classes
499
500
```java { .api }
501
public class ScaleXY {
502
public ScaleXY();
503
public ScaleXY(float scaleX, float scaleY);
504
505
public float getScaleX();
506
public float getScaleY();
507
public void set(float scaleX, float scaleY);
508
509
@Override
510
public String toString();
511
}
512
513
public interface KeyPathElement {
514
void resolveKeyPath(KeyPath keyPath, int depth, List<KeyPath> accumulator, KeyPath currentPartialKeyPath);
515
void addValueCallback(T property, LottieValueCallback<T> callback);
516
}
517
```