Skip to content

Commit 7b28195

Browse files
committed
fix(android): src is now loaded sync. You can change the behavior with the new async property
1 parent 927a64f commit 7b28195

File tree

3 files changed

+110
-47
lines changed

3 files changed

+110
-47
lines changed

plugin/platforms/android/native-api-usage.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@
44
"com.airbnb.lottie.model:KeyPath",
55
"com.airbnb.lottie.value:LottieValueCallback",
66
"com.airbnb.lottie:LottieProperty",
7+
"com.airbnb.lottie:SimpleColorFilter",
78
"com.airbnb.lottie:RenderMode",
89
"android.animation:Animator",
9-
"android.animation:Animator.AnimatorListener"
10+
"android.animation:Animator.AnimatorListener",
11+
"com.airbnb.lottie:LottieResult",
12+
"com.airbnb.lottie:LottieOnCompositionLoadedListener",
13+
"com.airbnb.lottie:LottieComposition",
14+
"com.airbnb.lottie:LottieCompositionFactory"
1015
]
1116
}

src/lottie.android.ts

Lines changed: 97 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,26 @@ import { clamp } from './utils';
2020
let LottieProperty: typeof com.airbnb.lottie.LottieProperty;
2121
let LottieKeyPath: typeof com.airbnb.lottie.model.KeyPath;
2222
let LottieValueCallback: typeof com.airbnb.lottie.value.LottieValueCallback;
23+
let LottieCompositionFactory: typeof com.airbnb.lottie.LottieCompositionFactory;
2324

2425
const cache = new Map();
25-
function loadLottieJSON(iconSrc) {
26+
async function loadLottieJSON(iconSrc) {
2627
if (!cache.has(iconSrc)) {
2728
const file = File.fromPath(iconSrc);
28-
return file.readText().then((r) => {
29-
cache.set(iconSrc, r);
30-
return r;
31-
});
29+
const r = await file.readText();
30+
cache.set(iconSrc, r);
31+
return r;
3232
}
33-
return Promise.resolve(cache.get(iconSrc));
33+
return cache.get(iconSrc);
34+
}
35+
function loadLottieJSONSync(iconSrc) {
36+
if (!cache.has(iconSrc)) {
37+
const file = File.fromPath(iconSrc);
38+
const r = file.readTextSync();
39+
cache.set(iconSrc, r);
40+
return r;
41+
}
42+
return cache.get(iconSrc);
3443
}
3544

3645
export const RenderMode = {
@@ -52,7 +61,8 @@ export class LottieView extends LottieViewBase {
5261
return new com.nativescript.lottie.LottieAnimationView(this._context);
5362
}
5463

55-
animatorListener;
64+
animatorListener: android.animation.Animator.AnimatorListener;
65+
loadedListener: com.airbnb.lottie.LottieOnCompositionLoadedListener;
5666
_completionBlock;
5767
//@ts-ignore
5868
get completionBlock() {
@@ -95,58 +105,104 @@ export class LottieView extends LottieViewBase {
95105
if (this.animatorListener) {
96106
this.nativeViewProtected.addAnimatorListener(this.animatorListener);
97107
}
98-
// if (this.src) {
99-
// this[srcProperty.setNative](this.src);
100-
// }
101-
102-
// if (this.loop) {
103-
// this.nativeView.loop(this.loop);
104-
// }
108+
if (!this.loadedListener) {
109+
this.loadedListener = new com.airbnb.lottie.LottieOnCompositionLoadedListener({
110+
onCompositionLoaded: (composition) => {
111+
this.notify({ eventName: 'compositionLoaded', composition });
112+
}
113+
});
114+
}
115+
this.nativeViewProtected.addLottieOnCompositionLoadedListener(this.loadedListener);
105116

106-
// if (this.autoPlay) {
107-
// this.playAnimation();
108-
// }
109117
}
110118

111119
public disposeNativeView(): void {
112120
if (this.animatorListener) {
113121
this.nativeViewProtected.removeAnimatorListener(this.animatorListener);
114122
}
123+
if (this.loadedListener) {
124+
this.nativeViewProtected.removeLottieOnCompositionLoadedListener(this.loadedListener);
125+
}
115126
super.disposeNativeView();
116127
}
117128

118129
[srcProperty.setNative](src: string) {
119-
const view = this.nativeViewProtected;
120-
if (!src) {
121-
// lottie does not support "clearing the animation"
122-
// view.setAnimation(null);
123-
} else if (src[0] === '{') {
124-
view.setAnimationFromJson(src, null);
125-
} else if (src.startsWith(Utils.RESOURCE_PREFIX)) {
126-
const resName = src.replace(Utils.RESOURCE_PREFIX, '');
127-
view.setAnimation(resName);
128-
} else {
129-
if (!/.(json|zip|lottie)$/.test(src)) {
130-
src += '.json';
130+
try {
131+
if (LottieCompositionFactory) {
132+
LottieCompositionFactory = com.airbnb.lottie.LottieCompositionFactory;
131133
}
132-
if (src[0] === '~') {
133-
this.nativeView.setAnimation('app/' + src.substring(2));
134-
} else if (!src.startsWith('file:/') && src[0] !== '/') {
135-
this.nativeView.setAnimation(src);
134+
const view = this.nativeViewProtected;
135+
let result: com.airbnb.lottie.LottieResult<com.airbnb.lottie.LottieComposition>;
136+
if (!src) {
137+
// lottie does not support "clearing the animation"
138+
// view.setAnimation(null);
139+
} else if (src[0] === '{') {
140+
if (this.async) {
141+
view.setAnimationFromJson(src, null);
142+
} else {
143+
result = LottieCompositionFactory.fromJsonStringSync(this._context, src);
144+
}
145+
} else if (src.startsWith(Utils.RESOURCE_PREFIX)) {
146+
const resName = src.replace(Utils.RESOURCE_PREFIX, '');
147+
if (this.async) {
148+
view.setAnimation(resName);
149+
} else {
150+
result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(this._context, resName);
151+
}
136152
} else {
137-
loadLottieJSON(src).then((r) => {
138-
this.nativeView.setAnimationFromJson(r, null);
139-
});
153+
if (!/.(json|zip|lottie)$/.test(src)) {
154+
src += '.json';
155+
}
156+
if (src[0] === '~') {
157+
if (this.async) {
158+
view.setAnimation('app/' + src.substring(2));
159+
} else {
160+
result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(
161+
this._context,
162+
'app/' + src.substring(2)
163+
);
164+
}
165+
} else if (!src.startsWith('file:/') && src[0] !== '/') {
166+
if (this.async) {
167+
view.setAnimation('app/' + src);
168+
} else {
169+
result = com.airbnb.lottie.LottieCompositionFactory.fromAssetSync(this._context, src);
170+
}
171+
} else {
172+
if (this.async) {
173+
loadLottieJSON(src).then((result) => {
174+
if (this.nativeViewProtected) {
175+
this.nativeViewProtected.setAnimationFromJson(result, null);
176+
}
177+
});
178+
} else {
179+
result = LottieCompositionFactory.fromJsonStringSync(this._context, loadLottieJSONSync(src));
180+
}
181+
}
140182
}
141-
}
142-
143-
if (this.autoPlay) {
144-
this.playAnimation();
183+
if (result) {
184+
if (result.getException()) {
185+
console.error(result.getException());
186+
// view.setComposition(null);
187+
} else {
188+
view.setComposition(result.getValue());
189+
//in sync loading we need to fire it ourselves
190+
// if we dont differ it from now it wont be received
191+
setTimeout(() => {
192+
this.notify({ eventName: 'compositionLoaded', composition: result.getValue() });
193+
}, 0);
194+
}
195+
}
196+
if (this.autoPlay) {
197+
this.playAnimation();
198+
}
199+
} catch (error) {
200+
console.error(error);
145201
}
146202
}
147203

148204
[loopProperty.setNative](loop: boolean) {
149-
this.nativeViewProtected.loop(loop);
205+
this.nativeViewProtected.setRepeatCount(loop ? -1 /* android.animation.ValueAnimator.INFINITE */ : 0);
150206
}
151207
[renderModeProperty.setNative](renderMode) {
152208
this.nativeViewProtected.setRenderMode(renderMode);
@@ -205,11 +261,6 @@ export class LottieView extends LottieViewBase {
205261
// LottieProperty.COLOR,
206262
// new LottieValueCallback(java.lang.Integer.valueOf(value.android))
207263
// );
208-
nativeView.addValueCallback(
209-
new LottieKeyPath(nativeKeyPath as any),
210-
LottieProperty.COLOR,
211-
new LottieValueCallback(java.lang.Integer.valueOf(value.android))
212-
);
213264
}
214265
}
215266

src/lottie.common.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { CoreTypes, Property, View, booleanConverter } from '@nativescript/core'
99

1010
export class LottieViewBase extends View {
1111
public stretch: CoreTypes.ImageStretchType;
12+
public async: boolean;
1213
public src: string;
1314
public loop: boolean;
1415
public autoPlay: boolean;
@@ -21,6 +22,12 @@ export const srcProperty = new Property<LottieViewBase, string>({
2122
});
2223
srcProperty.register(LottieViewBase);
2324

25+
export const asyncProperty = new Property<LottieViewBase, boolean>({
26+
name: 'async',
27+
defaultValue: false,
28+
valueConverter: booleanConverter
29+
});
30+
asyncProperty.register(LottieViewBase);
2431
export const loopProperty = new Property<LottieViewBase, boolean>({
2532
name: 'loop',
2633
defaultValue: false,

0 commit comments

Comments
 (0)