0
# Asset Management
1
2
Delegate interfaces for handling custom image assets, fonts, and dynamic text replacement. This system allows you to provide custom implementations for loading images, fonts, and replacing text content at runtime.
3
4
## Capabilities
5
6
### Image Asset Management
7
8
System for providing custom bitmap loading for image assets referenced in Lottie animations. Useful for loading images from network, custom storage, or applying transformations.
9
10
```java { .api }
11
/**
12
* Delegate for handling custom image asset loading
13
*/
14
public interface ImageAssetDelegate {
15
/**
16
* Fetch bitmap for the given image asset
17
* @param asset The image asset to load
18
* @return Bitmap to use, or null to use default loading
19
*/
20
Bitmap fetchBitmap(LottieImageAsset asset);
21
}
22
23
/**
24
* Image asset model containing metadata
25
*/
26
public class LottieImageAsset {
27
// Asset identification
28
public String getId();
29
public String getFileName();
30
public String getDirName();
31
32
// Dimensions
33
public int getWidth();
34
public int getHeight();
35
36
// Bitmap management
37
public Bitmap getBitmap();
38
public void setBitmap(Bitmap bitmap);
39
40
// Internal methods
41
@RestrictTo(RestrictTo.Scope.LIBRARY)
42
public boolean hasBitmap();
43
}
44
```
45
46
**Usage Examples:**
47
48
```java
49
// Basic image asset delegate
50
animationView.setImageAssetDelegate(new ImageAssetDelegate() {
51
@Override
52
public Bitmap fetchBitmap(LottieImageAsset asset) {
53
// Load from custom location
54
String imagePath = "custom/path/" + asset.getFileName();
55
return BitmapFactory.decodeFile(imagePath);
56
}
57
});
58
59
// Network image loading delegate
60
animationView.setImageAssetDelegate(new ImageAssetDelegate() {
61
@Override
62
public Bitmap fetchBitmap(LottieImageAsset asset) {
63
try {
64
String imageUrl = "https://cdn.example.com/images/" + asset.getFileName();
65
URL url = new URL(imageUrl);
66
InputStream inputStream = url.openConnection().getInputStream();
67
return BitmapFactory.decodeStream(inputStream);
68
} catch (IOException e) {
69
Log.e("Lottie", "Failed to load image: " + asset.getFileName(), e);
70
return null; // Use default loading
71
}
72
}
73
});
74
75
// Cached image loading with transformations
76
public class CachedImageDelegate implements ImageAssetDelegate {
77
private final LruCache<String, Bitmap> imageCache;
78
private final Context context;
79
80
public CachedImageDelegate(Context context) {
81
this.context = context;
82
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
83
int cacheSize = maxMemory / 8; // Use 1/8th of available memory
84
this.imageCache = new LruCache<String, Bitmap>(cacheSize) {
85
@Override
86
protected int sizeOf(String key, Bitmap bitmap) {
87
return bitmap.getByteCount() / 1024;
88
}
89
};
90
}
91
92
@Override
93
public Bitmap fetchBitmap(LottieImageAsset asset) {
94
String cacheKey = asset.getId();
95
Bitmap cached = imageCache.get(cacheKey);
96
if (cached != null) {
97
return cached;
98
}
99
100
// Load and process image
101
Bitmap original = loadImageFromAssets(asset.getFileName());
102
if (original != null) {
103
// Apply transformations
104
Bitmap processed = applyImageTransformations(original, asset);
105
imageCache.put(cacheKey, processed);
106
return processed;
107
}
108
109
return null;
110
}
111
112
private Bitmap loadImageFromAssets(String fileName) {
113
try (InputStream inputStream = context.getAssets().open("images/" + fileName)) {
114
return BitmapFactory.decodeStream(inputStream);
115
} catch (IOException e) {
116
return null;
117
}
118
}
119
120
private Bitmap applyImageTransformations(Bitmap original, LottieImageAsset asset) {
121
// Apply scaling, filters, etc.
122
if (original.getWidth() != asset.getWidth() || original.getHeight() != asset.getHeight()) {
123
return Bitmap.createScaledBitmap(original, asset.getWidth(), asset.getHeight(), true);
124
}
125
return original;
126
}
127
}
128
129
// Dynamic image replacement based on user data
130
animationView.setImageAssetDelegate(new ImageAssetDelegate() {
131
@Override
132
public Bitmap fetchBitmap(LottieImageAsset asset) {
133
switch (asset.getId()) {
134
case "user_avatar":
135
return getUserAvatarBitmap();
136
case "product_image":
137
return getProductImageBitmap();
138
default:
139
return null; // Use default loading
140
}
141
}
142
143
private Bitmap getUserAvatarBitmap() {
144
// Load user's profile picture
145
return ImageLoader.loadUserAvatar(getCurrentUserId());
146
}
147
148
private Bitmap getProductImageBitmap() {
149
// Load current product image
150
return ImageLoader.loadProductImage(getCurrentProductId());
151
}
152
});
153
```
154
155
### Font Asset Management
156
157
System for providing custom font loading for text layers in Lottie animations. Allows loading fonts from custom locations or applying font substitutions.
158
159
```java { .api }
160
/**
161
* Delegate for handling custom font asset loading
162
*/
163
public interface FontAssetDelegate {
164
/**
165
* Fetch typeface for the given font family
166
* @param fontFamily Font family name from animation
167
* @return Typeface to use, or null to use default loading
168
*/
169
Typeface fetchFont(String fontFamily);
170
171
/**
172
* Get file path for font family (optional)
173
* @param fontFamily Font family name
174
* @return Font file path, or null
175
*/
176
String getFontPath(String fontFamily);
177
}
178
179
/**
180
* Font asset model
181
*/
182
public class Font {
183
// Font identification
184
public String getName();
185
public String getFontFamily();
186
public String getStyle();
187
public String getFontPath();
188
189
// Font metrics
190
public float getAscent();
191
192
// Internal methods
193
@RestrictTo(RestrictTo.Scope.LIBRARY)
194
public Font(String fontFamily, String name, String style, float ascent);
195
}
196
```
197
198
**Usage Examples:**
199
200
```java
201
// Basic font asset delegate
202
animationView.setFontAssetDelegate(new FontAssetDelegate() {
203
@Override
204
public Typeface fetchFont(String fontFamily) {
205
try {
206
return Typeface.createFromAsset(getAssets(), "fonts/" + fontFamily + ".ttf");
207
} catch (Exception e) {
208
Log.w("Lottie", "Failed to load font: " + fontFamily, e);
209
return null; // Use default font
210
}
211
}
212
213
@Override
214
public String getFontPath(String fontFamily) {
215
return "fonts/" + fontFamily + ".ttf";
216
}
217
});
218
219
// Font mapping delegate
220
animationView.setFontAssetDelegate(new FontAssetDelegate() {
221
private final Map<String, String> fontMappings = new HashMap<String, String>() {{
222
put("CustomFont-Regular", "Roboto-Regular");
223
put("CustomFont-Bold", "Roboto-Bold");
224
put("DisplayFont", "Oswald-Regular");
225
}};
226
227
@Override
228
public Typeface fetchFont(String fontFamily) {
229
String mappedFont = fontMappings.get(fontFamily);
230
if (mappedFont != null) {
231
try {
232
return Typeface.createFromAsset(getAssets(), "fonts/" + mappedFont + ".ttf");
233
} catch (Exception e) {
234
Log.w("Lottie", "Failed to load mapped font: " + mappedFont, e);
235
}
236
}
237
238
// Try original font name
239
try {
240
return Typeface.createFromAsset(getAssets(), "fonts/" + fontFamily + ".ttf");
241
} catch (Exception e) {
242
return Typeface.DEFAULT;
243
}
244
}
245
246
@Override
247
public String getFontPath(String fontFamily) {
248
String mappedFont = fontMappings.get(fontFamily);
249
return "fonts/" + (mappedFont != null ? mappedFont : fontFamily) + ".ttf";
250
}
251
});
252
253
// System font delegate
254
animationView.setFontAssetDelegate(new FontAssetDelegate() {
255
@Override
256
public Typeface fetchFont(String fontFamily) {
257
switch (fontFamily.toLowerCase()) {
258
case "roboto":
259
case "roboto-regular":
260
return Typeface.DEFAULT;
261
case "roboto-bold":
262
return Typeface.DEFAULT_BOLD;
263
case "monospace":
264
return Typeface.MONOSPACE;
265
case "serif":
266
return Typeface.SERIF;
267
case "sans-serif":
268
return Typeface.SANS_SERIF;
269
default:
270
// Try to create from system
271
return Typeface.create(fontFamily, Typeface.NORMAL);
272
}
273
}
274
275
@Override
276
public String getFontPath(String fontFamily) {
277
return null; // System fonts don't have file paths
278
}
279
});
280
281
// Font caching delegate
282
public class CachedFontDelegate implements FontAssetDelegate {
283
private final Map<String, Typeface> fontCache = new HashMap<>();
284
private final Context context;
285
286
public CachedFontDelegate(Context context) {
287
this.context = context;
288
}
289
290
@Override
291
public Typeface fetchFont(String fontFamily) {
292
Typeface cached = fontCache.get(fontFamily);
293
if (cached != null) {
294
return cached;
295
}
296
297
try {
298
Typeface typeface = Typeface.createFromAsset(
299
context.getAssets(),
300
"fonts/" + fontFamily + ".ttf"
301
);
302
fontCache.put(fontFamily, typeface);
303
return typeface;
304
} catch (Exception e) {
305
Log.w("Lottie", "Failed to load font: " + fontFamily, e);
306
return Typeface.DEFAULT;
307
}
308
}
309
310
@Override
311
public String getFontPath(String fontFamily) {
312
return "fonts/" + fontFamily + ".ttf";
313
}
314
}
315
```
316
317
### Text Replacement
318
319
System for dynamically replacing text content in text layers. Allows localization, personalization, and real-time text updates.
320
321
```java { .api }
322
/**
323
* Delegate for dynamic text replacement
324
*/
325
public class TextDelegate {
326
// Text replacement methods
327
public String getText(String layerName, String sourceText);
328
public void setText(String layerName, String text);
329
330
// Internal text storage
331
private final Map<String, String> textMap = new HashMap<>();
332
333
// Internal callback handling
334
@RestrictTo(RestrictTo.Scope.LIBRARY)
335
public final LottieValueCallback<String> getTextCallback(String layerName, String sourceText);
336
}
337
```
338
339
**Usage Examples:**
340
341
```java
342
// Basic text replacement
343
TextDelegate textDelegate = new TextDelegate() {
344
@Override
345
public String getText(String layerName, String sourceText) {
346
switch (layerName) {
347
case "WelcomeText":
348
return "Welcome, " + getCurrentUserName() + "!";
349
case "StatusText":
350
return getApplicationStatus();
351
case "CounterText":
352
return String.valueOf(getCurrentCount());
353
default:
354
return sourceText; // Use original text
355
}
356
}
357
};
358
animationView.setTextDelegate(textDelegate);
359
360
// Localized text replacement
361
TextDelegate localizedDelegate = new TextDelegate() {
362
private final Map<String, String> localizedTexts = loadLocalizedTexts();
363
364
@Override
365
public String getText(String layerName, String sourceText) {
366
String localized = localizedTexts.get(layerName);
367
return localized != null ? localized : sourceText;
368
}
369
370
private Map<String, String> loadLocalizedTexts() {
371
Map<String, String> texts = new HashMap<>();
372
// Load from resources based on current locale
373
String locale = Locale.getDefault().getLanguage();
374
switch (locale) {
375
case "es":
376
texts.put("HelloText", "¡Hola!");
377
texts.put("GoodbyeText", "¡Adiós!");
378
break;
379
case "fr":
380
texts.put("HelloText", "Bonjour!");
381
texts.put("GoodbyeText", "Au revoir!");
382
break;
383
default:
384
texts.put("HelloText", "Hello!");
385
texts.put("GoodbyeText", "Goodbye!");
386
break;
387
}
388
return texts;
389
}
390
};
391
392
// Dynamic text updates
393
TextDelegate dynamicDelegate = new TextDelegate();
394
animationView.setTextDelegate(dynamicDelegate);
395
396
// Update text dynamically
397
dynamicDelegate.setText("ScoreText", "Score: " + currentScore);
398
dynamicDelegate.setText("TimeText", "Time: " + formatTime(remainingTime));
399
dynamicDelegate.setText("MessageText", "Level " + currentLevel + " Complete!");
400
401
// Template-based text replacement
402
TextDelegate templateDelegate = new TextDelegate() {
403
@Override
404
public String getText(String layerName, String sourceText) {
405
// Support template variables in source text
406
return replaceTemplateVariables(sourceText);
407
}
408
409
private String replaceTemplateVariables(String template) {
410
return template
411
.replace("${username}", getCurrentUserName())
412
.replace("${score}", String.valueOf(getCurrentScore()))
413
.replace("${level}", String.valueOf(getCurrentLevel()))
414
.replace("${date}", getCurrentDate());
415
}
416
};
417
418
// Real-time updating text delegate
419
public class LiveTextDelegate extends TextDelegate {
420
private Timer updateTimer;
421
private LottieAnimationView animationView;
422
423
public LiveTextDelegate(LottieAnimationView animationView) {
424
this.animationView = animationView;
425
startUpdates();
426
}
427
428
@Override
429
public String getText(String layerName, String sourceText) {
430
switch (layerName) {
431
case "ClockText":
432
return getCurrentTime();
433
case "CountdownText":
434
return String.valueOf(getRemainingSeconds());
435
case "LiveDataText":
436
return getLiveDataValue();
437
default:
438
return sourceText;
439
}
440
}
441
442
private void startUpdates() {
443
updateTimer = new Timer();
444
updateTimer.scheduleAtFixedRate(new TimerTask() {
445
@Override
446
public void run() {
447
// Trigger redraw to update text
448
if (animationView != null) {
449
animationView.post(() -> animationView.invalidate());
450
}
451
}
452
}, 0, 1000); // Update every second
453
}
454
455
public void stopUpdates() {
456
if (updateTimer != null) {
457
updateTimer.cancel();
458
updateTimer = null;
459
}
460
}
461
462
private String getCurrentTime() {
463
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
464
return sdf.format(new Date());
465
}
466
467
private int getRemainingSeconds() {
468
// Calculate remaining time
469
return Math.max(0, (int) ((endTime - System.currentTimeMillis()) / 1000));
470
}
471
472
private String getLiveDataValue() {
473
// Fetch live data from server, database, etc.
474
return String.valueOf(DataProvider.getCurrentValue());
475
}
476
}
477
478
// Conditional text replacement
479
TextDelegate conditionalDelegate = new TextDelegate() {
480
@Override
481
public String getText(String layerName, String sourceText) {
482
switch (layerName) {
483
case "StatusIndicator":
484
return isConnected() ? "ONLINE" : "OFFLINE";
485
case "ProgressText":
486
int progress = getCurrentProgress();
487
if (progress < 25) return "Starting...";
488
else if (progress < 75) return "In Progress...";
489
else if (progress < 100) return "Almost Done...";
490
else return "Complete!";
491
case "UserGreeting":
492
return isUserLoggedIn() ?
493
"Welcome back!" :
494
"Please sign in";
495
default:
496
return sourceText;
497
}
498
}
499
};
500
```
501
502
## Font Character Model
503
504
```java { .api }
505
public class FontCharacter {
506
// Character properties
507
public String getCharacter();
508
public double getSize();
509
public double getWidth();
510
public String getStyle();
511
public String getFontFamily();
512
513
// Shape data
514
public List<ShapeGroup> getShapes();
515
516
// Internal construction
517
@RestrictTo(RestrictTo.Scope.LIBRARY)
518
public FontCharacter(List<ShapeGroup> shapes, String character, double size,
519
double width, String style, String fontFamily);
520
}
521
```