@react-native-ohos/lottie-react-native 7.2.3-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.OpenSource +11 -0
- package/README.md +13 -0
- package/harmony/lottie/BuildProfile.ets +21 -0
- package/harmony/lottie/build-profile.json5 +8 -0
- package/harmony/lottie/hvigorfile.ts +5 -0
- package/harmony/lottie/index.ets +5 -0
- package/harmony/lottie/oh-package.json5 +14 -0
- package/harmony/lottie/src/main/cpp/CMakeLists.txt +9 -0
- package/harmony/lottie/src/main/cpp/LottieAnimationViewPackage.h +13 -0
- package/harmony/lottie/src/main/cpp/generated/RNOH/generated/BaseLottieReactNativePackage.h +68 -0
- package/harmony/lottie/src/main/cpp/generated/RNOH/generated/components/LottieAnimationViewJSIBinder.h +43 -0
- package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/ComponentDescriptors.h +22 -0
- package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/EventEmitters.cpp +44 -0
- package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/EventEmitters.h +39 -0
- package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/Props.cpp +41 -0
- package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/Props.h +42 -0
- package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/ShadowNodes.cpp +19 -0
- package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/ShadowNodes.h +34 -0
- package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/States.cpp +18 -0
- package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/States.h +36 -0
- package/harmony/lottie/src/main/ets/LottieAnimationTools.ets +21 -0
- package/harmony/lottie/src/main/ets/LottieAnimationView.ets +393 -0
- package/harmony/lottie/src/main/ets/LottieAnimationViewPackage.ts +17 -0
- package/harmony/lottie/src/main/ets/LottieCompositionCache.ets +30 -0
- package/harmony/lottie/src/main/ets/common/Animation.ts +43 -0
- package/harmony/lottie/src/main/ets/common/AnimationType.ets +50 -0
- package/harmony/lottie/src/main/ets/common/TextUtils.ets +18 -0
- package/harmony/lottie/src/main/ets/generated/components/LottieAnimationView.ts +181 -0
- package/harmony/lottie/src/main/ets/generated/components/ts.ts +5 -0
- package/harmony/lottie/src/main/ets/generated/index.ets +5 -0
- package/harmony/lottie/src/main/ets/generated/ts.ts +6 -0
- package/harmony/lottie/src/main/ets/generated/turboModules/ts.ts +5 -0
- package/harmony/lottie/src/main/module.json5 +9 -0
- package/harmony/lottie/src/main/resources/base/element/string.json +8 -0
- package/harmony/lottie/src/main/resources/base/media/icon.png +0 -0
- package/harmony/lottie/src/main/resources/en_US/element/string.json +8 -0
- package/harmony/lottie/src/main/resources/zh_CN/element/string.json +8 -0
- package/harmony/lottie/ts.ts +5 -0
- package/harmony/lottie.har +0 -0
- package/lib/commonjs/LottieAnimationViewNativeComponent.js +18 -0
- package/lib/commonjs/LottieAnimationViewNativeComponent.js.map +1 -0
- package/lib/commonjs/codegenUtils.js +2 -0
- package/lib/commonjs/codegenUtils.js.map +1 -0
- package/lib/commonjs/index.js +25 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/module/LottieAnimationViewNativeComponent.js +11 -0
- package/lib/module/LottieAnimationViewNativeComponent.js.map +1 -0
- package/lib/module/codegenUtils.js +2 -0
- package/lib/module/codegenUtils.js.map +1 -0
- package/lib/module/index.js +8 -0
- package/lib/module/index.js.map +1 -0
- package/lib/typescript/LottieAnimationViewNativeComponent.d.ts +44 -0
- package/lib/typescript/LottieAnimationViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/codegenUtils.d.ts +3 -0
- package/lib/typescript/codegenUtils.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +4 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/package.json +131 -0
- package/src/LottieAnimationViewNativeComponent.ts +78 -0
- package/src/codegenUtils.ts +9 -0
- package/src/index.tsx +7 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
|
4
|
+
*
|
|
5
|
+
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
|
6
|
+
* once the code is regenerated.
|
|
7
|
+
*
|
|
8
|
+
* @generated by codegen project: GenerateShadowNodeH.js
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#pragma once
|
|
12
|
+
|
|
13
|
+
#include <react/renderer/components/lottie_react_native/EventEmitters.h>
|
|
14
|
+
#include <react/renderer/components/lottie_react_native/Props.h>
|
|
15
|
+
#include <react/renderer/components/lottie_react_native/States.h>
|
|
16
|
+
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
17
|
+
#include <jsi/jsi.h>
|
|
18
|
+
|
|
19
|
+
namespace facebook {
|
|
20
|
+
namespace react {
|
|
21
|
+
|
|
22
|
+
JSI_EXPORT extern const char LottieAnimationViewComponentName[];
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
* `ShadowNode` for <LottieAnimationView> component.
|
|
26
|
+
*/
|
|
27
|
+
using LottieAnimationViewShadowNode = ConcreteViewShadowNode<
|
|
28
|
+
LottieAnimationViewComponentName,
|
|
29
|
+
LottieAnimationViewProps,
|
|
30
|
+
LottieAnimationViewEventEmitter,
|
|
31
|
+
LottieAnimationViewState>;
|
|
32
|
+
|
|
33
|
+
} // namespace react
|
|
34
|
+
} // namespace facebook
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
|
4
|
+
*
|
|
5
|
+
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
|
6
|
+
* once the code is regenerated.
|
|
7
|
+
*
|
|
8
|
+
* @generated by codegen project: GenerateStateCpp.js
|
|
9
|
+
*/
|
|
10
|
+
#include <react/renderer/components/lottie_react_native/States.h>
|
|
11
|
+
|
|
12
|
+
namespace facebook {
|
|
13
|
+
namespace react {
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
} // namespace react
|
|
18
|
+
} // namespace facebook
|
package/harmony/lottie/src/main/cpp/generated/react/renderer/components/lottie_react_native/States.h
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
|
3
|
+
*
|
|
4
|
+
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
|
5
|
+
* once the code is regenerated.
|
|
6
|
+
*
|
|
7
|
+
* @generated by codegen project: GenerateStateH.js
|
|
8
|
+
*/
|
|
9
|
+
#pragma once
|
|
10
|
+
|
|
11
|
+
#ifdef ANDROID
|
|
12
|
+
#include <folly/dynamic.h>
|
|
13
|
+
#include <react/renderer/mapbuffer/MapBuffer.h>
|
|
14
|
+
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
namespace facebook {
|
|
18
|
+
namespace react {
|
|
19
|
+
|
|
20
|
+
class LottieAnimationViewState {
|
|
21
|
+
public:
|
|
22
|
+
LottieAnimationViewState() = default;
|
|
23
|
+
|
|
24
|
+
#ifdef ANDROID
|
|
25
|
+
LottieAnimationViewState(LottieAnimationViewState const &previousState, folly::dynamic data){};
|
|
26
|
+
folly::dynamic getDynamic() const {
|
|
27
|
+
return {};
|
|
28
|
+
};
|
|
29
|
+
MapBuffer getMapBuffer() const {
|
|
30
|
+
return MapBufferBuilder::EMPTY();
|
|
31
|
+
};
|
|
32
|
+
#endif
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
} // namespace react
|
|
36
|
+
} // namespace facebook
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a Apache-2.0 license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import { AnimationObject, AnimationAssets } from './common/Animation'
|
|
6
|
+
import { isEmpty } from './common/TextUtils'
|
|
7
|
+
|
|
8
|
+
export function convertImageFolder(jsonData: AnimationObject, imagesFolder: string): AnimationObject {
|
|
9
|
+
let assets: AnimationAssets[] = jsonData.assets
|
|
10
|
+
if (assets != undefined && assets.length > 0 && !isEmpty(imagesFolder)) {
|
|
11
|
+
if (imagesFolder.charAt(imagesFolder.length - 1) != '/') {
|
|
12
|
+
imagesFolder = imagesFolder + '/'
|
|
13
|
+
}
|
|
14
|
+
let assetsTemp: AnimationAssets[] = assets.map((obj: AnimationAssets) => {
|
|
15
|
+
obj.u = imagesFolder
|
|
16
|
+
return obj
|
|
17
|
+
})
|
|
18
|
+
jsonData.assets = assetsTemp
|
|
19
|
+
}
|
|
20
|
+
return jsonData
|
|
21
|
+
}
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a Apache-2.0 license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import { RNOHContext, RNViewBase } from '@rnoh/react-native-openharmony';
|
|
6
|
+
import lottie from '@ohos/lottie';
|
|
7
|
+
import { AnimationItem } from '@ohos/lottie';
|
|
8
|
+
import http from '@ohos.net.http';
|
|
9
|
+
import { colorFiltersItem, LOTTLE_STRING } from './common/AnimationType';
|
|
10
|
+
import { AnimationObject, layersItem } from './common/Animation';
|
|
11
|
+
import { LottieCompositionCache } from './LottieCompositionCache';
|
|
12
|
+
import { convertImageFolder } from './LottieAnimationTools';
|
|
13
|
+
import { getHashCode } from './common/TextUtils';
|
|
14
|
+
import { RNOHLogger } from "@rnoh/react-native-openharmony/ts";
|
|
15
|
+
import { RNC } from './generated';
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Use LottieAnimationView.NAME instead
|
|
18
|
+
*/
|
|
19
|
+
export const LOTTIE_TYPE: string = RNC.LottieAnimationView.NAME
|
|
20
|
+
|
|
21
|
+
@Component
|
|
22
|
+
export struct LottieAnimationView {
|
|
23
|
+
public static readonly NAME = RNC.LottieAnimationView.NAME
|
|
24
|
+
ctx!: RNOHContext;
|
|
25
|
+
tag: number = 0;
|
|
26
|
+
private logger!: RNOHLogger
|
|
27
|
+
@State descriptorWrapper: RNC.LottieAnimationView.DescriptorWrapper = {} as RNC.LottieAnimationView.DescriptorWrapper;
|
|
28
|
+
private unregisterDescriptorChangesListener?: () => void = undefined;
|
|
29
|
+
@State @Watch('onStateChanged') progress: number = 0;
|
|
30
|
+
@State @Watch('onStateChanged') speed: number = 1;
|
|
31
|
+
@State @Watch('onStateChanged') loop: boolean = true;
|
|
32
|
+
@State @Watch('onStateChanged') autoPlay: boolean = false;
|
|
33
|
+
@State @Watch('onStateChanged') cacheComposition: boolean = true;
|
|
34
|
+
private jsonData: AnimationObject | null = {} as AnimationObject;
|
|
35
|
+
private jsonDataHashCode: string = '';
|
|
36
|
+
private cleanupCommandCallback?: () => void = undefined;
|
|
37
|
+
private renderingSettings: RenderingContextSettings = new RenderingContextSettings(true);
|
|
38
|
+
private canvasRenderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.renderingSettings);
|
|
39
|
+
private animateItem: AnimationItem | null = null;
|
|
40
|
+
private lottieCache = LottieCompositionCache.getInstance();
|
|
41
|
+
private animateKey: string | null = null;
|
|
42
|
+
private eventEmitter: RNC.LottieAnimationView.EventEmitter | undefined = undefined
|
|
43
|
+
|
|
44
|
+
aboutToAppear() {
|
|
45
|
+
// 创建EventEmitter实例,用于处理事件的订阅和触发
|
|
46
|
+
this.eventEmitter = new RNC.LottieAnimationView.EventEmitter(this.ctx.rnInstance, this.tag)
|
|
47
|
+
this.logger = this.ctx!.logger.clone(RNC.LottieAnimationView.NAME)
|
|
48
|
+
this.onDescriptorWrapperChange(this.ctx.descriptorRegistry.findDescriptorWrapperByTag<RNC.LottieAnimationView.DescriptorWrapper>(this.tag)!)
|
|
49
|
+
this.commandCallback();
|
|
50
|
+
this.subscribeToDescriptorChanges();
|
|
51
|
+
lottie.bindContext2dToCoordinator(this.canvasRenderingContext)
|
|
52
|
+
this.logger.info(`testlottie:${JSON.stringify(this.descriptorWrapper.props)}`)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private onDescriptorWrapperChange(descriptorWrapper: RNC.LottieAnimationView.DescriptorWrapper) {
|
|
56
|
+
this.descriptorWrapper = descriptorWrapper
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
aboutToDisappear() {
|
|
60
|
+
this.cleanupCommandCallback?.();
|
|
61
|
+
this.unregisterDescriptorChangesListener?.();
|
|
62
|
+
this.destroyAnimation();
|
|
63
|
+
if (this.animateKey) {
|
|
64
|
+
lottie.destroy(this.animateKey);
|
|
65
|
+
}
|
|
66
|
+
this.animateKey = null;
|
|
67
|
+
lottie.unbindContext2dFromCoordinator(this.canvasRenderingContext)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
subscribeToDescriptorChanges(): void {
|
|
71
|
+
this.unregisterDescriptorChangesListener = this.ctx.descriptorRegistry.subscribeToDescriptorChanges(this.tag,
|
|
72
|
+
(newDescriptor: object) => {
|
|
73
|
+
this.descriptorWrapper = (newDescriptor as RNC.LottieAnimationView.DescriptorWrapper);
|
|
74
|
+
this.onDescriptorChanged(true);
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
onDescriptorChanged(change?: boolean): void {
|
|
80
|
+
if (this.descriptorWrapper.props) {
|
|
81
|
+
this.handleColorFilters();
|
|
82
|
+
this.updateWatchData();
|
|
83
|
+
change && this.parseSourceURL();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
onStateChanged(propName: string): void {
|
|
88
|
+
if (this.animateItem == null) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
switch (propName) {
|
|
92
|
+
case LOTTLE_STRING.progress:
|
|
93
|
+
this.setProgress();
|
|
94
|
+
break;
|
|
95
|
+
case LOTTLE_STRING.speed:
|
|
96
|
+
this.setSpeed();
|
|
97
|
+
break;
|
|
98
|
+
case LOTTLE_STRING.loop: {
|
|
99
|
+
this.animateItem.loop = this.loop;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case LOTTLE_STRING.autoPlay:
|
|
103
|
+
this.setAutoPlay();
|
|
104
|
+
break;
|
|
105
|
+
default:
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
onAnimationFinish(isCancelled: boolean): void {
|
|
111
|
+
this.eventEmitter!.emit("animationFinish", {isCancelled: isCancelled});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
onAnimationCancel(): void {
|
|
115
|
+
this.onAnimationFinish(true);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
onAnimationEnd(): void {
|
|
119
|
+
this.onAnimationFinish(false);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
cacheProcessing(data: string, isURL?: boolean): void {
|
|
123
|
+
const hashCode = getHashCode(data);
|
|
124
|
+
if (hashCode === this.jsonDataHashCode) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (this.descriptorWrapper.props.cacheComposition) {
|
|
128
|
+
const tempJsonObj = this.getCacheData(hashCode);
|
|
129
|
+
if (tempJsonObj) {
|
|
130
|
+
this.jsonData = tempJsonObj;
|
|
131
|
+
this.jsonDataHashCode = hashCode;
|
|
132
|
+
this.initAnimation();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (isURL) {
|
|
137
|
+
this.request(data, hashCode);
|
|
138
|
+
} else {
|
|
139
|
+
this.updateJsonData(data, hashCode);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
parseSourceURL(): void {
|
|
144
|
+
if (!this.descriptorWrapper?.props) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (this.descriptorWrapper.props.sourceURL &&
|
|
148
|
+
this.descriptorWrapper.props.sourceURL.startsWith(LOTTLE_STRING.http)) {
|
|
149
|
+
this.cacheProcessing(this.descriptorWrapper.props.sourceURL, true);
|
|
150
|
+
} else {
|
|
151
|
+
this.descriptorWrapper.props.sourceJson && this.cacheProcessing(this.descriptorWrapper.props.sourceJson);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
request(url: string, hashCode?: string): void {
|
|
156
|
+
this.logger.debug('httpRequest.request url:', url);
|
|
157
|
+
const httpRequest = http.createHttp();
|
|
158
|
+
httpRequest.request(url, { header: { [LOTTLE_STRING.contentType]: LOTTLE_STRING.json } }, (err, data) => {
|
|
159
|
+
if (err == undefined && data != undefined) {
|
|
160
|
+
this.logger.debug('httpRequest.request success:', JSON.stringify(data));
|
|
161
|
+
const result: Object = data.result;
|
|
162
|
+
if (result) {
|
|
163
|
+
this.updateJsonData(result as string, hashCode);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
this.logger.error('httpRequest.request error:', `errorCode: ${err?.code}`);
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
updateWatchData(): void {
|
|
172
|
+
this.progress = this.descriptorWrapper.props.progress;
|
|
173
|
+
this.speed = this.descriptorWrapper.props.speed;
|
|
174
|
+
this.loop = Boolean(this.descriptorWrapper.props.loop);
|
|
175
|
+
this.autoPlay = Boolean(this.descriptorWrapper.props.autoPlay);
|
|
176
|
+
this.cacheComposition = Boolean(this.descriptorWrapper.props.cacheComposition);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
updateJsonData(data: string, hashCode?: string): void {
|
|
180
|
+
try {
|
|
181
|
+
this.jsonData =
|
|
182
|
+
convertImageFolder(JSON.parse(data) as AnimationObject,
|
|
183
|
+
this.descriptorWrapper.props.imageAssetsFolder as string);
|
|
184
|
+
this.initAnimation();
|
|
185
|
+
this.setCacheData(this.jsonData as AnimationObject, hashCode);
|
|
186
|
+
} catch (e) {
|
|
187
|
+
this.logger.error('updateJsonData,source parse error');
|
|
188
|
+
this.jsonData = null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
setCacheData(jsonObj: AnimationObject, key?: string): void {
|
|
193
|
+
if (key) {
|
|
194
|
+
this.lottieCache.set(key, jsonObj);
|
|
195
|
+
this.jsonDataHashCode = key;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
getCacheData(key: string): AnimationObject | null {
|
|
200
|
+
return this.lottieCache.get(key);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
initAnimation(): void {
|
|
204
|
+
if (this.jsonData == null) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
this.loadAnimation();
|
|
208
|
+
this.setSpeed();
|
|
209
|
+
this.addEventFrameListener();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
destroyAnimation(): void {
|
|
213
|
+
if (this.animateItem == null) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (this.animateItem.isPaused === false) {
|
|
217
|
+
this.onAnimationEnd();
|
|
218
|
+
}
|
|
219
|
+
lottie.destroy(this.animateKey);
|
|
220
|
+
this.animateItem = null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
loadAnimation(): void {
|
|
224
|
+
this.destroyAnimation();
|
|
225
|
+
this.animateKey = `${this.tag}${new Date().getTime()}`;
|
|
226
|
+
this.animateItem = lottie.loadAnimation({
|
|
227
|
+
container: this.canvasRenderingContext,
|
|
228
|
+
renderer: LOTTLE_STRING.canvas,
|
|
229
|
+
name: this.animateKey,
|
|
230
|
+
loop: Boolean(this.descriptorWrapper.props.loop),
|
|
231
|
+
autoplay: Boolean(this.descriptorWrapper.props.autoPlay),
|
|
232
|
+
animationData: this.jsonData
|
|
233
|
+
});
|
|
234
|
+
this.animateItem?.addEventListener(LOTTLE_STRING.DOMLoaded, () => {
|
|
235
|
+
try{
|
|
236
|
+
let upperResizeMode =
|
|
237
|
+
this.descriptorWrapper.props?.resizeMode?.replace(this.descriptorWrapper.props.resizeMode[0],
|
|
238
|
+
this.descriptorWrapper.props.resizeMode[0].toUpperCase())
|
|
239
|
+
this.eventEmitter!.emit("animationLoaded", {});
|
|
240
|
+
this.animateItem?.setContentMode(upperResizeMode);
|
|
241
|
+
this.onDescriptorChanged();
|
|
242
|
+
}catch(e) {
|
|
243
|
+
this.logger.error('DOMLoaded catch error:', e);
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
this.animateItem?.addEventListener(LOTTLE_STRING.data_failed, () => {
|
|
247
|
+
this.eventEmitter!.emit("animationFailure", {error: 'data_failed'});
|
|
248
|
+
})
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
handleColorFilters(): void {
|
|
252
|
+
const layersData: Array<layersItem> = this.jsonData?.layers ?? [];
|
|
253
|
+
const colorFiltersData: Array<colorFiltersItem> =
|
|
254
|
+
(this.descriptorWrapper.props.colorFilters ?? []) as Array<colorFiltersItem>;
|
|
255
|
+
for (const item of colorFiltersData) {
|
|
256
|
+
const index: number = layersData.findIndex((layersItem: layersItem) => layersItem?.nm === item?.keypath);
|
|
257
|
+
const color: Array<number> = this.getColorByColorFilters(item);
|
|
258
|
+
const isIndex: boolean = index !== (-1);
|
|
259
|
+
const isColor: boolean = color.length === 3;
|
|
260
|
+
if (isIndex && isColor) {
|
|
261
|
+
this.animateItem?.changeColor(color, index + 1);
|
|
262
|
+
this.logger.debug('colorFilters success:', item?.keypath);
|
|
263
|
+
} else {
|
|
264
|
+
this.logger.error('colorFilters fail:not find keyPath', item?.keypath);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
getColorByColorFilters(colorFiltersItem: colorFiltersItem): Array<number> {
|
|
270
|
+
const color: string = colorFiltersItem?.color;
|
|
271
|
+
if (color) {
|
|
272
|
+
const processColor: number = Number(color);
|
|
273
|
+
const r: number = (processColor >> 16) & 0xff;
|
|
274
|
+
const g: number = (processColor >> 8) & 0xff;
|
|
275
|
+
const b: number = processColor & 0xff;
|
|
276
|
+
this.logger.debug(`getColorByColorFilters, r=${r}, g=${g}, b=${b}`);
|
|
277
|
+
return [r, g, b];
|
|
278
|
+
}
|
|
279
|
+
this.logger.error('colorFilters fail:not find color', colorFiltersItem?.keypath);
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
setProgress(): void {
|
|
284
|
+
const frame = this.getAnimateFrame();
|
|
285
|
+
this.animateItem?.goToAndStop(frame, true);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
setSpeed(): void {
|
|
289
|
+
this.animateItem?.setSpeed(this.descriptorWrapper.props.speed);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
setAutoPlay(): void {
|
|
293
|
+
this.animateItem?.goToAndPlay(this.getAnimateFrame(), true);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
getAnimateFrame(): number {
|
|
297
|
+
const firstFrame: number = this.animateItem?.firstFrame ?? 0;
|
|
298
|
+
const totalFrames: number = this.animateItem?.totalFrames ?? 0;
|
|
299
|
+
return Math.ceil(firstFrame + this.descriptorWrapper.props.progress * totalFrames);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
addEventFrameListener(): void {
|
|
303
|
+
this.completeEvent();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
completeEvent(): void {
|
|
307
|
+
//动画播放结束且不再播放动画触发
|
|
308
|
+
this.animateItem?.addEventListener(LOTTLE_STRING.complete, () => {
|
|
309
|
+
this.onAnimationFinish(false);
|
|
310
|
+
})
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
commandCallback(): void {
|
|
314
|
+
this.cleanupCommandCallback = this.ctx.componentCommandReceiver.registerCommandCallback(
|
|
315
|
+
this.tag,
|
|
316
|
+
(command: string, args: object) => {
|
|
317
|
+
if (this.animateItem == null) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
switch (command) {
|
|
321
|
+
case LOTTLE_STRING.play:
|
|
322
|
+
this.play(args as number[]);
|
|
323
|
+
break;
|
|
324
|
+
case LOTTLE_STRING.reset:
|
|
325
|
+
this.reset();
|
|
326
|
+
break;
|
|
327
|
+
case LOTTLE_STRING.pause:
|
|
328
|
+
this.pause();
|
|
329
|
+
break;
|
|
330
|
+
case LOTTLE_STRING.resume:
|
|
331
|
+
this.resume();
|
|
332
|
+
break;
|
|
333
|
+
default:
|
|
334
|
+
this.logger.warn('not find command');
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
})
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
play(args: number[]): void {
|
|
341
|
+
const startFrame = args[0];
|
|
342
|
+
const endFrame = args[1];
|
|
343
|
+
this.animateItem?.stop();
|
|
344
|
+
if (this.progress !== 0) {
|
|
345
|
+
this.progress = 0;
|
|
346
|
+
this.animateItem?.goToAndPlay(this.getAnimateFrame(), true);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (args.length > 1 && startFrame != -1 && endFrame != -1) {
|
|
350
|
+
if (startFrame > endFrame) {
|
|
351
|
+
this.animateItem?.setSegment(endFrame, startFrame);
|
|
352
|
+
if (this.descriptorWrapper.props.speed > 0) {
|
|
353
|
+
this.animateItem?.setDirection(-1);
|
|
354
|
+
}
|
|
355
|
+
} else {
|
|
356
|
+
this.animateItem?.setSegment(startFrame, endFrame);
|
|
357
|
+
if (this.descriptorWrapper.props.speed < 0) {
|
|
358
|
+
this.animateItem?.setDirection(-1);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
this.animateItem?.play();
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
reset(): void {
|
|
366
|
+
this.animateItem?.stop();
|
|
367
|
+
this.onAnimationEnd();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
pause(): void {
|
|
371
|
+
this.animateItem?.pause();
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
resume(): void {
|
|
375
|
+
if (this.animateItem?.isPaused) {
|
|
376
|
+
this.animateItem?.togglePause();
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
resize(): void {
|
|
381
|
+
this.animateItem?.resize();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
build() {
|
|
385
|
+
RNViewBase({ ctx: this.ctx, tag: this.tag }) {
|
|
386
|
+
Canvas(this.canvasRenderingContext)
|
|
387
|
+
.width('100%')
|
|
388
|
+
.height('100%')
|
|
389
|
+
.onReady(() => this.parseSourceURL())
|
|
390
|
+
.onAreaChange(() => this.resize())
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a Apache-2.0 license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import { RNPackage } from '@rnoh/react-native-openharmony/ts';
|
|
6
|
+
import type {DescriptorWrapperFactoryByDescriptorTypeCtx, DescriptorWrapperFactoryByDescriptorType} from '@rnoh/react-native-openharmony/ts';
|
|
7
|
+
import { RNC } from './generated/ts';
|
|
8
|
+
|
|
9
|
+
export class LottieAnimationViewPackage extends RNPackage {
|
|
10
|
+
createDescriptorWrapperFactoryByDescriptorType(ctx:
|
|
11
|
+
DescriptorWrapperFactoryByDescriptorTypeCtx):
|
|
12
|
+
DescriptorWrapperFactoryByDescriptorType {
|
|
13
|
+
return {
|
|
14
|
+
[RNC.LottieAnimationView.NAME]: (ctx) => new RNC.LottieAnimationView.DescriptorWrapper(ctx.descriptor)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a Apache-2.0 license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import HashMap from '@ohos.util.HashMap'
|
|
6
|
+
import { AnimationObject } from './common/Animation'
|
|
7
|
+
|
|
8
|
+
export class LottieCompositionCache {
|
|
9
|
+
private static readonly sInstance: LottieCompositionCache = new LottieCompositionCache()
|
|
10
|
+
private cache: HashMap<String, AnimationObject> = new HashMap()
|
|
11
|
+
|
|
12
|
+
public static getInstance(): LottieCompositionCache {
|
|
13
|
+
return LottieCompositionCache.sInstance
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get(cacheKey: string): AnimationObject | null {
|
|
17
|
+
return cacheKey ? this.cache.get(cacheKey) : null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
set(cacheKey: string, composition: AnimationObject): void {
|
|
21
|
+
if (cacheKey.length === 0) {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
this.cache.set(cacheKey, composition)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
clear(): void {
|
|
28
|
+
this.cache.clear()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a Apache-2.0 license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
export interface layersItem {
|
|
6
|
+
"ddd"?: number;
|
|
7
|
+
"ind"?: number;
|
|
8
|
+
"ty"?: number;
|
|
9
|
+
"nm"?: string;
|
|
10
|
+
"sr"?: number;
|
|
11
|
+
"ks": object;
|
|
12
|
+
"ao"?: number;
|
|
13
|
+
"shapes": Array<{ [key: string]: string | number }>
|
|
14
|
+
"ip"?: number;
|
|
15
|
+
"op"?: number;
|
|
16
|
+
"st"?: number;
|
|
17
|
+
"bm"?: number;
|
|
18
|
+
|
|
19
|
+
[key: string]: string | number | object | [];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type AnimationObject = {
|
|
23
|
+
v: string
|
|
24
|
+
fr: number
|
|
25
|
+
ip: number
|
|
26
|
+
op: number
|
|
27
|
+
w: number
|
|
28
|
+
h: number
|
|
29
|
+
nm?: string
|
|
30
|
+
ddd?: number
|
|
31
|
+
assets: AnimationAssets[]
|
|
32
|
+
layers: layersItem[]
|
|
33
|
+
markers?: Object[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type AnimationAssets = {
|
|
37
|
+
id: string
|
|
38
|
+
w: number
|
|
39
|
+
h: number
|
|
40
|
+
u: string
|
|
41
|
+
p: string
|
|
42
|
+
e: number
|
|
43
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a Apache-2.0 license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import { ViewRawProps } from '@rnoh/react-native-openharmony'
|
|
6
|
+
|
|
7
|
+
export interface LottieViewState {}
|
|
8
|
+
|
|
9
|
+
export interface colorFiltersItem {
|
|
10
|
+
keypath: string;
|
|
11
|
+
color: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface LottieViewProps extends ViewRawProps {
|
|
15
|
+
resizeMode: string
|
|
16
|
+
renderMode: string
|
|
17
|
+
sourceName: string
|
|
18
|
+
sourceJson: string
|
|
19
|
+
sourceURL: string
|
|
20
|
+
imageAssetsFolder: string
|
|
21
|
+
progress: number
|
|
22
|
+
speed: number
|
|
23
|
+
loop: boolean
|
|
24
|
+
autoPlay: boolean
|
|
25
|
+
enableMergePathsAndroidForKitKatAndAbove: boolean
|
|
26
|
+
hardwareAccelerationAndroid: boolean
|
|
27
|
+
cacheComposition: boolean
|
|
28
|
+
colorFilters: Array<colorFiltersItem>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export enum LOTTLE_STRING {
|
|
32
|
+
onStateChanged = 'onStateChanged',
|
|
33
|
+
progress = 'progress',
|
|
34
|
+
speed = 'speed',
|
|
35
|
+
loop = 'loop',
|
|
36
|
+
autoPlay = 'autoPlay',
|
|
37
|
+
onAnimationFinish = 'onAnimationFinish',
|
|
38
|
+
http = 'http',
|
|
39
|
+
contentType = 'Content-Type',
|
|
40
|
+
json = 'application/json',
|
|
41
|
+
canvas = 'canvas',
|
|
42
|
+
DOMLoaded = 'DOMLoaded',
|
|
43
|
+
colorFilters = 'colorFilters',
|
|
44
|
+
complete = 'complete',
|
|
45
|
+
play = 'play',
|
|
46
|
+
reset = 'reset',
|
|
47
|
+
pause = 'pause',
|
|
48
|
+
resume = 'resume',
|
|
49
|
+
data_failed = 'data_failed'
|
|
50
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a Apache-2.0 license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
export function isEmpty(str: string | null | undefined): boolean {
|
|
6
|
+
return str == null || typeof str == 'undefined' || str.length == 0
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getHashCode(str: string): string {
|
|
10
|
+
let hash: number = 1315423911
|
|
11
|
+
let i: number
|
|
12
|
+
let ch: number
|
|
13
|
+
for (i = str.length - 1; i >= 0; i--) {
|
|
14
|
+
ch = str.charCodeAt(i)
|
|
15
|
+
hash ^= ((hash << 5) + ch + (hash >> 2))
|
|
16
|
+
}
|
|
17
|
+
return (hash & 0x7FFFFFFF).toString()
|
|
18
|
+
}
|