rn-newarch-svga-player 1.1.4 → 1.1.6

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/README.md ADDED
@@ -0,0 +1,108 @@
1
+ ## **这是一款使用 ReactNative 新架构 加载`Android/iOS` Svga 动画的开源插件**[三端 Svga 动画统一使用点击这里](https://github.com/yrjwcharm/react-native-ohos/tree/feature/rnoh/svgaplayer)
2
+
3
+ > ### 版本:latest
4
+
5
+ <p align="center">
6
+ <h1 align="center"> <code>rn-newarch-svga-player</code> </h1>
7
+ </p>
8
+ <p align="center">
9
+ <a href="https://github.com/wonday/react-native-pdf/blob/master/LICENSE">
10
+ <img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License" />
11
+ </a>
12
+ </p>
13
+
14
+ > [!TIP] [Github 地址](https://github.com/yrjwcharm/rn-newarch-svga-player)
15
+
16
+ ## 安装与使用
17
+
18
+ > [!TIP] 注意 ⚠️ 本库 android/ios 仅给予 Fabric 新架构 支持,旧架构不在跟进,若需旧架构支持请移步<https://github.com/yrjwcharm/react-native-svga-player>
19
+
20
+ #### **npm**
21
+
22
+ ```bash
23
+ npm install rn-newarch-svga-player
24
+ ```
25
+
26
+ #### **yarn**
27
+
28
+ ```bash
29
+ yarn add rn-newarch-svga-player
30
+ ```
31
+
32
+ ## API 参考
33
+
34
+ ### Props
35
+
36
+ | 属性 | 类型 | 默认值 | 描述 |
37
+ | ----------------- | ------------------------- | ----------- | ----------------------------------------------------- |
38
+ | `source` | `SvgaSource` | - | SVGA 文件源 |
39
+ | `autoPlay` | `boolean` | `true` | 是否自动播放 |
40
+ | `loops` | `number` | `0` | 循环播放次数,默认值:0 表示无限循环 |
41
+ | `clearsAfterStop` | `boolean` | `true` | 动画停止后是否清空画布 |
42
+ | `fillMode` | `'Forward' \| 'Backward'` | `'Forward'` | 填充模式:Forward 停留在最后一帧,Backward 回到第一帧 |
43
+ | `onFinished` | `function` | - | 播放完成时的回调函数 |
44
+ | `onFrame` | `function` | - | 帧变化时的回调函数 |
45
+ | `onPercentage` | `function` | - | 播放进度变化时的回调函数 |
46
+
47
+ ### Ref 方法
48
+
49
+ | 方法 | 描述 |
50
+ | ---------------------------------------------------- | ----------------------------------------------- |
51
+ | `startAnimation()` | 从第 0 帧开始播放动画 |
52
+ | `startAnimationWithRange(location, length, reverse)` | 在指定范围内播放动画,可选择反向播放 |
53
+ | `pauseAnimation()` | 暂停动画,停留在当前帧 |
54
+ | `stopAnimation()` | 停止动画,根据 clearsAfterStop 决定是否清空画布 |
55
+ | `stepToFrame(frame, andPlay)` | 跳转到指定帧,可选择是否从该帧开始播放 |
56
+ | `stepToPercentage(percentage, andPlay)` | 跳转到指定百分比位置 (0.0-1.0),可选择是否播放 |
57
+
58
+ > 若想更改库的别名 react-native-svga-player 来导入。你则需要把 rn-newarch-svga-player 库修改下,重新 yarn 执行
59
+
60
+ ```diff
61
+ + "dependencies": {
62
+ "@react-native-oh/react-native-harmony": "0.72.48",
63
+ "patch-package": "^8.0.0",
64
+ "postinstall-postinstall": "^2.1.0",
65
+ "react": "18.2.0",
66
+ "react-native": "0.72.5",
67
+ - "rn-newarch-svga-player":"^1.1.6"
68
+ + "react-native-svga-player":"npm:rn-newarch-svga-player@1.1.6"
69
+ },
70
+ ```
71
+
72
+ 下面的代码展示了这个库的基本使用场景:
73
+
74
+ ```js
75
+ import React from "react";
76
+ import { View, Dimensions, StyleSheet } from "react-native";
77
+ import { RNSvgaPlayer } from "react-native-svga-player";
78
+
79
+ export function App() {
80
+ return (
81
+ <RNSvgaPlayer
82
+ source="https://raw.githubusercontent.com/yyued/SVGAPlayer-iOS/master/SVGAPlayer/Samples/Goddess.svga"
83
+ style={{
84
+ width: 300,
85
+ height: 150,
86
+ }}
87
+ />
88
+ );
89
+ }
90
+
91
+ const styles = StyleSheet.create({
92
+ container: {
93
+ flex: 1,
94
+ justifyContent: "flex-start",
95
+ alignItems: "center",
96
+ },
97
+ });
98
+ ```
99
+
100
+ 更多详情用法参考 [三端 Svga 动画统一使用点击这里](https://github.com/yrjwcharm/react-native-ohos/tree/feature/rnoh/svgaplayer)
101
+
102
+ #### 开源不易,希望您可以动一动小手点点小 ⭐⭐
103
+
104
+ #### 👴 希望大家如有好的需求踊跃提交,如有问题请提交 issue,空闲时间会扩充与修复优化
105
+
106
+ ## 开源协议
107
+
108
+ 本项目基于 [The MIT License (MIT)](https://github.com/yrjwcharm/react-native-ohos-svgaplayer/blob/master/LICENSE) ,请自由地享受和参与开源。
package/SvgaPlayer.tsx CHANGED
@@ -1,22 +1,21 @@
1
1
  import React, { forwardRef, useImperativeHandle, useRef } from 'react';
2
2
  import type { ViewProps } from 'react-native';
3
- import RNSvgaPlayerNative, {
3
+ import SvgaPlayerView, {
4
4
  Commands,
5
5
  type ComponentType,
6
6
  } from './src/specs/SvgaPlayerNativeComponent';
7
-
8
7
  export interface SvgaErrorEvent {
9
8
  error: string;
10
9
  }
11
10
 
12
11
  export interface SvgaPlayerProps extends ViewProps {
13
- source?: string;
12
+ source: string;
14
13
  /**
15
14
  * 是否自动播放,默认 true
16
15
  */
17
16
  autoPlay?: boolean;
18
17
  /**
19
- * 循环播放次数,默认 0(无限循环)
18
+ * 循环播放次数,默认 0(无限循环播放)
20
19
  */
21
20
  loops?: number;
22
21
  /**
@@ -28,10 +27,14 @@ export interface SvgaPlayerProps extends ViewProps {
28
27
  */
29
28
  align?: 'top' | 'bottom' | 'center';
30
29
 
30
+ fillMode?: 'Forward' | 'Backward';
31
+
31
32
  // 事件回调
32
33
  onError?: (event: SvgaErrorEvent) => void;
33
34
  onFinished?: () => void;
34
35
  onLoaded?: () => void;
36
+ onFrame?: (event: { value: number }) => void;
37
+ onPercentage?: (event: { value: number }) => void;
35
38
  }
36
39
 
37
40
  export interface SvgaPlayerRef {
@@ -43,6 +46,14 @@ export interface SvgaPlayerRef {
43
46
  * 停止动画,如果 clearsAfterStop 为 true 则清空画布
44
47
  */
45
48
  stopAnimation: () => void;
49
+ pauseAnimation: () => void;
50
+ stepToFrame: (frame: number, andPlay: boolean) => void;
51
+ stepToPercentage: (percentage: number, andPlay: boolean) => void;
52
+ startAnimationWithRange: (
53
+ location: number,
54
+ length: number,
55
+ reverse: boolean
56
+ ) => void;
46
57
  }
47
58
 
48
59
  const RNSvgaPlayer = forwardRef<SvgaPlayerRef, SvgaPlayerProps>(
@@ -50,11 +61,13 @@ const RNSvgaPlayer = forwardRef<SvgaPlayerRef, SvgaPlayerProps>(
50
61
  {
51
62
  autoPlay = true,
52
63
  loops = 0,
53
- clearsAfterStop = false,
54
- source,
64
+ clearsAfterStop = true,
65
+ source = '',
55
66
  onError,
56
67
  onFinished,
57
68
  onLoaded,
69
+ onFrame,
70
+ onPercentage,
58
71
  ...restProps
59
72
  },
60
73
  ref
@@ -72,22 +85,48 @@ const RNSvgaPlayer = forwardRef<SvgaPlayerRef, SvgaPlayerProps>(
72
85
  Commands.stopAnimation(nativeRef.current);
73
86
  }
74
87
  },
75
- // pauseAnimation: () => {
76
- // if (nativeRef.current) {
77
- // Commands.pauseAnimation(nativeRef.current);
78
- // }
79
- // },
88
+ pauseAnimation: () => {
89
+ if (nativeRef.current) {
90
+ Commands.pauseAnimation(nativeRef.current);
91
+ }
92
+ },
93
+ stepToFrame: (frame: number, andPlay: boolean) => {
94
+ if (nativeRef.current) {
95
+ Commands.stepToFrame(nativeRef.current, frame, andPlay);
96
+ }
97
+ },
98
+ stepToPercentage: (frame: number, andPlay: boolean) => {
99
+ if (nativeRef.current) {
100
+ Commands.stepToPercentage(nativeRef.current, frame, andPlay);
101
+ }
102
+ },
103
+ startAnimationWithRange: (
104
+ location: number,
105
+ length: number,
106
+ reverse: boolean
107
+ ) => {
108
+ if (nativeRef.current) {
109
+ Commands.startAnimationWithRange(
110
+ nativeRef.current,
111
+ location,
112
+ length,
113
+ reverse
114
+ );
115
+ }
116
+ },
80
117
  }));
81
118
 
82
119
  return (
83
- <RNSvgaPlayerNative
120
+ <SvgaPlayerView
84
121
  ref={nativeRef}
85
122
  source={source}
86
123
  autoPlay={autoPlay}
87
124
  loops={loops}
88
125
  clearsAfterStop={clearsAfterStop}
89
- onError={(error) => onError?.(error.nativeEvent)}
126
+ onError={(event) => onError?.(event.nativeEvent)}
90
127
  onFinished={onFinished}
128
+ onFrameChanged={(event) => onFrame?.(event.nativeEvent)}
129
+ onPercentageChanged={(event) => onPercentage?.(event.nativeEvent)}
91
130
  onLoaded={onLoaded}
92
131
  {...restProps}
93
132
  />
@@ -15,7 +15,7 @@ buildscript {
15
15
  }
16
16
 
17
17
  dependencies {
18
- classpath "com.android.tools.build:gradle:8.7.2"
18
+ classpath "com.android.tools.build:gradle:7.3.1"
19
19
  // noinspection DifferentKotlinGradleVersion
20
20
  classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
21
21
  }
@@ -24,7 +24,6 @@ buildscript {
24
24
 
25
25
  apply plugin: "com.android.library"
26
26
  apply plugin: "kotlin-android"
27
-
28
27
  apply plugin: "com.facebook.react"
29
28
 
30
29
  def getExtOrIntegerDefault(name) {
@@ -1,5 +1,5 @@
1
- SvgaPlayer_kotlinVersion=2.0.21
2
- SvgaPlayer_minSdkVersion=24
3
- SvgaPlayer_targetSdkVersion=34
4
- SvgaPlayer_compileSdkVersion=35
5
- SvgaPlayer_ndkVersion=27.1.12297006
1
+ # SvgaPlayer_kotlinVersion=2.0.21
2
+ # SvgaPlayer_minSdkVersion=24
3
+ # SvgaPlayer_targetSdkVersion=34
4
+ # SvgaPlayer_compileSdkVersion=35
5
+ # SvgaPlayer_ndkVersion=27.1.12297006
@@ -11,6 +11,9 @@ import com.facebook.react.uimanager.events.EventDispatcher
11
11
  import com.opensource.svgaplayer.SVGACallback
12
12
  import com.opensource.svgaplayer.SVGAImageView
13
13
  import com.svgaplayer.events.TopFinishedEvent
14
+ import com.svgaplayer.events.TopFrameEvent
15
+ import com.svgaplayer.events.TopLoadedEvent
16
+ import com.svgaplayer.events.TopPercentageEvent
14
17
 
15
18
  class RNSvgaPlayer(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : SVGAImageView(context, attrs, defStyleAttr) {
16
19
 
@@ -23,6 +26,16 @@ class RNSvgaPlayer(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
23
26
  override fun onStep(frame: Int, percentage: Double) {
24
27
  // 动画开始播放,清除启动标记
25
28
  isStarting = false
29
+ val frameArguments = Arguments.createMap()
30
+ val percentageArguments = Arguments.createMap()
31
+ frameArguments.putDouble("value",frame.toDouble());
32
+ percentageArguments.putDouble("value", percentage);
33
+ val surfaceId = UIManagerHelper.getSurfaceId(context)
34
+ val framedEvent = TopFrameEvent(surfaceId, id, frameArguments)
35
+ var percentageEvent = TopPercentageEvent(surfaceId,id,percentageArguments);
36
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context as ThemedReactContext, id)
37
+ dispatcher?.dispatchEvent(framedEvent)
38
+ dispatcher?.dispatchEvent(percentageEvent);
26
39
  }
27
40
 
28
41
  override fun onRepeat() {
@@ -1,48 +1,45 @@
1
1
  package com.svgaplayer
2
2
 
3
- import android.content.Context
4
3
  import android.util.Log
5
- import com.facebook.infer.annotation.Assertions
4
+ import android.widget.ImageView
6
5
  import com.facebook.react.bridge.Arguments
7
- import com.facebook.react.bridge.ReactApplicationContext
8
6
  import com.facebook.react.bridge.ReadableArray
7
+ import com.facebook.react.common.MapBuilder
9
8
  import com.facebook.react.module.annotations.ReactModule
10
9
  import com.facebook.react.uimanager.SimpleViewManager
11
10
  import com.facebook.react.uimanager.ThemedReactContext
12
11
  import com.facebook.react.uimanager.UIManagerHelper
13
12
  import com.facebook.react.uimanager.ViewManagerDelegate
14
13
  import com.facebook.react.uimanager.annotations.ReactProp
15
- import android.widget.ImageView
16
14
  import com.facebook.react.viewmanagers.RNSvgaPlayerManagerDelegate
17
15
  import com.facebook.react.viewmanagers.RNSvgaPlayerManagerInterface
16
+ import com.opensource.svgaplayer.SVGACache
18
17
  import com.opensource.svgaplayer.SVGAParser
19
18
  import com.opensource.svgaplayer.SVGAVideoEntity
20
- import com.opensource.svgaplayer.SVGACache
19
+ import com.opensource.svgaplayer.utils.SVGARange
21
20
  import com.svgaplayer.events.TopErrorEvent
22
- import com.svgaplayer.events.TopFinishedEvent
23
21
  import com.svgaplayer.events.TopLoadedEvent
24
22
  import java.io.File
25
23
  import java.io.FileInputStream
26
- import java.io.IOException
27
24
  import java.net.URL
28
25
 
29
- @ReactModule(name = RNSvgaPlayerManager.NAME)
30
- class RNSvgaPlayerManager : SimpleViewManager<RNSvgaPlayer>(), RNSvgaPlayerManagerInterface<RNSvgaPlayer> {
26
+
27
+ @ReactModule(name = RNSvgaPlayerManager.REACT_CLASS)
28
+ class RNSvgaPlayerManager() : SimpleViewManager<RNSvgaPlayer>(), RNSvgaPlayerManagerInterface<RNSvgaPlayer> {
31
29
 
32
30
  companion object {
33
- const val NAME = "RNSvgaPlayer"
31
+ const val REACT_CLASS = "RNSvgaPlayer"
34
32
  }
35
-
36
33
  private val mDelegate: ViewManagerDelegate<RNSvgaPlayer> = RNSvgaPlayerManagerDelegate(this)
37
34
 
38
- override fun getName(): String = NAME
35
+ override fun getName(): String = REACT_CLASS
39
36
 
40
37
  override fun getDelegate(): ViewManagerDelegate<RNSvgaPlayer>? = mDelegate
41
38
 
42
39
  override fun createViewInstance(c: ThemedReactContext): RNSvgaPlayer {
43
40
  return RNSvgaPlayer(c, null, 0)
44
41
  }
45
-
42
+ @ReactProp(name = "source")
46
43
  override fun setSource(view: RNSvgaPlayer, source: String?) {
47
44
  val context = view.context
48
45
  source?.let {
@@ -67,7 +64,7 @@ class RNSvgaPlayerManager : SimpleViewManager<RNSvgaPlayer>(), RNSvgaPlayerManag
67
64
  val surfaceId = UIManagerHelper.getSurfaceId(context)
68
65
  val loadedEvent = TopLoadedEvent(surfaceId, view.id, loadedData)
69
66
  val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context as ThemedReactContext, view.id)
70
- dispatcher?.dispatchEvent(loadedEvent)
67
+ dispatcher?.dispatchEvent(loadedEvent)
71
68
 
72
69
  if(view.autoPlay){
73
70
  view.startAnimationSafely()
@@ -99,20 +96,20 @@ class RNSvgaPlayerManager : SimpleViewManager<RNSvgaPlayer>(), RNSvgaPlayerManag
99
96
  }
100
97
  }
101
98
  }
102
-
99
+ @ReactProp(name = "loops", defaultInt = 0)
103
100
  override fun setLoops(view: RNSvgaPlayer, loops: Int) {
104
101
  view.loops = loops
105
102
  }
106
-
103
+ @ReactProp(name = "clearsAfterStop", defaultBoolean = true)
107
104
  override fun setClearsAfterStop(view: RNSvgaPlayer, clearsAfterStop: Boolean) {
108
105
  view.clearsAfterDetached = clearsAfterStop
109
106
  view.clearsAfterStop = clearsAfterStop
110
107
  }
111
-
108
+ @ReactProp(name = "autoPlay", defaultBoolean = true)
112
109
  override fun setAutoPlay(view: RNSvgaPlayer, autoPlay: Boolean) {
113
110
  view.autoPlay = autoPlay
114
111
  }
115
-
112
+ @ReactProp(name = "align")
116
113
  override fun setAlign(view: RNSvgaPlayer, align: String?) {
117
114
  val scaleType = when (align) {
118
115
  "bottom" -> ImageView.ScaleType.FIT_END
@@ -130,6 +127,26 @@ class RNSvgaPlayerManager : SimpleViewManager<RNSvgaPlayer>(), RNSvgaPlayerManag
130
127
  when (commandId) {
131
128
  "startAnimation" -> startAnimation(root)
132
129
  "stopAnimation" -> stopAnimation(root)
130
+ "pauseAnimation" -> pauseAnimation(root)
131
+ "stepToFrame" -> {
132
+ val frame = args?.getInt(0) ?: 0
133
+ val andPlay = args?.getBoolean(1) ?: false
134
+ stepToFrame(root, frame, andPlay)
135
+ }
136
+ "stepToPercentage" -> {
137
+ val percentage = args?.getInt(0) ?: 0
138
+ val andPlay = args?.getBoolean(1) ?: false
139
+ stepToPercentage(root, percentage, andPlay)
140
+ }
141
+ "startAnimationWithRange" -> {
142
+ val location = args?.getInt(0) ?: 0
143
+ val length = args?.getInt(1) ?: 0
144
+ val reverse = args?.getBoolean(2) ?: false
145
+ startAnimationWithRange(root, location, length, reverse)
146
+ }
147
+ else -> {
148
+ Log.w(REACT_CLASS, "Unknown command: $commandId")
149
+ }
133
150
  }
134
151
  }
135
152
 
@@ -138,17 +155,51 @@ class RNSvgaPlayerManager : SimpleViewManager<RNSvgaPlayer>(), RNSvgaPlayerManag
138
155
  }
139
156
 
140
157
  override fun stopAnimation(view: RNSvgaPlayer) {
141
- view.stopAnimation(true)
158
+ view.stopAnimation(view.clearsAfterStop)
159
+ }
160
+
161
+ // override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any>? {
162
+ // val export = super.getExportedCustomDirectEventTypeConstants()?.toMutableMap()
163
+ // ?: mutableMapOf<String, Any>()
164
+ //
165
+ // export[TopErrorEvent.EVENT_NAME] = mapOf("registrationName" to "onError")
166
+ // export[TopFinishedEvent.EVENT_NAME] = mapOf("registrationName" to "onFinished")
167
+ // export[TopLoadedEvent.EVENT_NAME] = mapOf("registrationName" to "onLoaded")
168
+ // export[TopFrameEvent.EVENT_NAME] = mapOf("registrationName" to "onFrameChanged")
169
+ // export[TopPercentageEvent.EVENT_NAME] = mapOf("registrationName" to "onPercentageChanged")
170
+ //
171
+ // return export
172
+ // }
173
+ override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any>? {
174
+ val map = MapBuilder.builder<String, Any>()
175
+ .put("topError", MapBuilder.of("registrationName", "onError"))
176
+ .put("topFinished", MapBuilder.of("registrationName", "onFinished"))
177
+ .put("topLoaded", MapBuilder.of("registrationName", "onLoaded"))
178
+ .put("topFrameChanged", MapBuilder.of("registrationName", "onFrameChanged"))
179
+ .put("topPercentageChanged", MapBuilder.of("registrationName", "onPercentageChanged"))
180
+ .build()
181
+ return map
142
182
  }
143
183
 
144
- override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any>? {
145
- val export = super.getExportedCustomDirectEventTypeConstants()?.toMutableMap()
146
- ?: mutableMapOf<String, Any>()
184
+ override fun pauseAnimation(view: RNSvgaPlayer?) {
185
+ view?.pauseAnimation()
186
+ }
147
187
 
148
- export[TopErrorEvent.EVENT_NAME] = mapOf("registrationName" to "onError")
149
- export[TopFinishedEvent.EVENT_NAME] = mapOf("registrationName" to "onFinished")
150
- export[TopLoadedEvent.EVENT_NAME] = mapOf("registrationName" to "onLoaded")
188
+ override fun stepToFrame(view: RNSvgaPlayer?, frame: Int, andPlay: Boolean) {
189
+ view?.stepToFrame(frame, andPlay);
190
+ }
191
+
192
+ override fun stepToPercentage(view: RNSvgaPlayer?, percentage: Int, andPlay: Boolean) {
193
+ view?.stepToFrame(percentage, andPlay);
194
+ }
151
195
 
152
- return export
196
+ override fun startAnimationWithRange(
197
+ view: RNSvgaPlayer?,
198
+ location: Int,
199
+ length: Int,
200
+ reverse: Boolean
201
+ ) {
202
+ var range = SVGARange(location, length)
203
+ view?.startAnimation(range,reverse)
153
204
  }
154
205
  }
@@ -0,0 +1,19 @@
1
+ package com.svgaplayer.events
2
+
3
+ import com.facebook.react.bridge.WritableMap
4
+ import com.facebook.react.uimanager.events.Event
5
+
6
+ class TopFrameEvent(
7
+ surfaceId: Int,
8
+ viewTag: Int,
9
+ private val eventData: WritableMap
10
+ ) : Event<TopFrameEvent>(surfaceId, viewTag) {
11
+
12
+ companion object {
13
+ const val EVENT_NAME = "onFrameChanged"
14
+ }
15
+
16
+ override fun getEventName(): String = EVENT_NAME
17
+
18
+ override fun getEventData(): WritableMap? = eventData
19
+ }
@@ -0,0 +1,19 @@
1
+ package com.svgaplayer.events
2
+
3
+ import com.facebook.react.bridge.WritableMap
4
+ import com.facebook.react.uimanager.events.Event
5
+
6
+ class TopPercentageEvent(
7
+ surfaceId: Int,
8
+ viewTag: Int,
9
+ private val eventData: WritableMap
10
+ ) : Event<TopPercentageEvent>(surfaceId, viewTag) {
11
+
12
+ companion object {
13
+ const val EVENT_NAME = "onPercentageChanged"
14
+ }
15
+
16
+ override fun getEventName(): String = EVENT_NAME
17
+
18
+ override fun getEventData(): WritableMap? = eventData
19
+ }
@@ -7,11 +7,7 @@
7
7
 
8
8
  NS_ASSUME_NONNULL_BEGIN
9
9
 
10
- @interface RCTSvgaPlayer : RCTViewComponentView <SVGAPlayerDelegate>
11
-
12
- // Commands
13
- - (void)startAnimation;
14
- - (void)stopAnimation;
10
+ @interface RCTSvgaPlayer : RCTViewComponentView
15
11
 
16
12
  @end
17
13
 
@@ -25,11 +25,22 @@ using namespace facebook::react;
25
25
  SVGAVideoEntity * _currentVideoItem;
26
26
  }
27
27
 
28
+ // Event emitter convenience method
29
+ - (const RNSvgaPlayerEventEmitter &)eventEmitter
30
+ {
31
+ return static_cast<const RNSvgaPlayerEventEmitter &>(*_eventEmitter);
32
+ }
33
+
28
34
  + (ComponentDescriptorProvider)componentDescriptorProvider
29
35
  {
30
36
  return concreteComponentDescriptorProvider<RNSvgaPlayerComponentDescriptor>();
31
37
  }
32
38
 
39
+
40
+ Class<RCTComponentViewProtocol> RNSvgaPlayerCls(void)
41
+ {
42
+ return RCTSvgaPlayer.class;
43
+ }
33
44
  - (instancetype)initWithFrame:(CGRect)frame
34
45
  {
35
46
  if (self = [super initWithFrame:frame]) {
@@ -104,12 +115,6 @@ using namespace facebook::react;
104
115
 
105
116
  [super updateProps:props oldProps:oldProps];
106
117
  }
107
-
108
- Class<RCTComponentViewProtocol> SvgaPlayerViewCls(void)
109
- {
110
- return RCTSvgaPlayer.class;
111
- }
112
-
113
118
  // 辅助方法:根据 align 属性设置 contentMode
114
119
  - (void)updateContentModeWithAlign:(RNSvgaPlayerAlign)align
115
120
  {
@@ -135,21 +140,27 @@ Class<RCTComponentViewProtocol> SvgaPlayerViewCls(void)
135
140
  [_svgaPlayer setVideoItem:nil];
136
141
  [_svgaPlayer clear];
137
142
  _currentVideoItem = nil;
138
-
139
- if (_eventEmitter != nullptr) {
140
- std::dynamic_pointer_cast<const facebook::react::RNSvgaPlayerEventEmitter>(_eventEmitter)
141
- ->onError(facebook::react::RNSvgaPlayerEventEmitter::OnError{
142
- .error = std::string([errorMessage UTF8String])
143
- });
144
- }
143
+
144
+ RNSvgaPlayerEventEmitter::OnError result = RNSvgaPlayerEventEmitter::OnError{RNSvgaPlayerEventEmitter::OnError( [errorMessage UTF8String] )};
145
+ self.eventEmitter.onError(result);
146
+
147
+ // if (_eventEmitter != nullptr) {
148
+ // std::dynamic_pointer_cast<const facebook::react::RNSvgaPlayerEventEmitter>(_eventEmitter)
149
+ // ->onError(facebook::react::RNSvgaPlayerEventEmitter::OnError{
150
+ // .error = std::string([errorMessage UTF8String])
151
+ // });
152
+ // }
145
153
  }
146
154
 
147
155
  - (void)sendLoadedEvent
148
156
  {
149
- if (_eventEmitter != nullptr) {
150
- std::dynamic_pointer_cast<const facebook::react::RNSvgaPlayerEventEmitter>(_eventEmitter)
151
- ->onLoaded(facebook::react::RNSvgaPlayerEventEmitter::OnLoaded{});
152
- }
157
+ // if (_eventEmitter != nullptr) {
158
+ // std::dynamic_pointer_cast<const facebook::react::RNSvgaPlayerEventEmitter>(_eventEmitter)
159
+ // ->onLoaded(facebook::react::RNSvgaPlayerEventEmitter::OnLoaded{});
160
+ //
161
+ // }
162
+ RNSvgaPlayerEventEmitter::OnLoaded result = RNSvgaPlayerEventEmitter::OnLoaded{RNSvgaPlayerEventEmitter::OnLoaded( {} )};
163
+ self.eventEmitter.onLoaded(result);
153
164
  }
154
165
 
155
166
  // 辅助方法:处理文件路径
@@ -372,7 +383,34 @@ Class<RCTComponentViewProtocol> SvgaPlayerViewCls(void)
372
383
  {
373
384
  [_svgaPlayer stopAnimation];
374
385
  }
375
-
386
+ - (void)pauseAnimation {
387
+ [_svgaPlayer pauseAnimation];
388
+ }
389
+ -(void)stepToFrame:(NSInteger)frame andPlay:(BOOL)play {
390
+ if (frame < 0 || !_svgaPlayer || _svgaPlayer.delegate != self) {
391
+ return;
392
+ }
393
+ [_svgaPlayer stepToFrame:frame andPlay:play];
394
+ }
395
+ -(void)stepToPercentage:(NSInteger)percentage andPlay:(BOOL)play {
396
+ if (percentage < 0 || !_svgaPlayer || _svgaPlayer.delegate != self) {
397
+ return;
398
+ }
399
+ [_svgaPlayer stepToPercentage:percentage andPlay:play];
400
+ }
401
+ -(void)startAnimationWithRange:(NSInteger)location length:(NSInteger)length reverse:(BOOL)reverse{
402
+ if (!_svgaPlayer || _svgaPlayer.delegate != self) {
403
+ return;
404
+ }
405
+
406
+ // 检查 location 和 length 的有效性
407
+ if (location < 0 || length <= 0) {
408
+ return;
409
+ }
410
+ // 设置动画范围
411
+ [_svgaPlayer startAnimationWithRange:NSMakeRange(location, length) reverse:reverse];
412
+ }
413
+
376
414
  // 处理来自 JavaScript 的命令调用
377
415
  - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
378
416
  {
@@ -380,7 +418,43 @@ Class<RCTComponentViewProtocol> SvgaPlayerViewCls(void)
380
418
  [self startAnimation];
381
419
  } else if ([commandName isEqualToString:@"stopAnimation"]) {
382
420
  [self stopAnimation];
421
+ }else if ([commandName isEqualToString:@"pauseAnimation"]) {
422
+ [self pauseAnimation];
423
+ }else if([commandName isEqualToString:@"stepToFrame"]){
424
+ [self stepToFrame:[args[0] integerValue] andPlay:[args[1] boolValue]];
425
+
426
+ }else if([commandName isEqualToString:@"stepToPercentage"]){
427
+ [self stepToPercentage:[args[0] integerValue] andPlay:[args[1] boolValue]];
428
+
429
+ }else if([commandName isEqualToString:@"startAnimationWithRange"]){
430
+ // 处理 startAnimationWithRange 命令
431
+ [self startAnimationWithRange:[args[0] integerValue]
432
+ length:[args[1] integerValue]
433
+ reverse:[args[2] boolValue]];
383
434
  }
435
+
436
+ }
437
+ -(void) svgaPlayerDidAnimatedToFrame:(NSInteger)frame{
438
+ if (!_svgaPlayer || _svgaPlayer.delegate != self) {
439
+ return;
440
+ }
441
+ RNSvgaPlayerEventEmitter::OnFrameChanged result = RNSvgaPlayerEventEmitter::OnFrameChanged{RNSvgaPlayerEventEmitter::OnFrameChanged( frame )};
442
+ self.eventEmitter.onFrameChanged(result);
443
+ // std::dynamic_pointer_cast<const RNSvgaPlayerEventEmitter>(_eventEmitter)
444
+ // ->onFrameChanged(RNSvgaPlayerEventEmitter::OnFrameChanged{.value=(float)frame});
445
+
446
+ }
447
+ -(void) svgaPlayerDidAnimatedToPercentage:(CGFloat)percentage{
448
+ // 检查播放器是否还有效
449
+ if (!_svgaPlayer || _svgaPlayer.delegate != self) {
450
+ return;
451
+ }
452
+
453
+ RNSvgaPlayerEventEmitter::OnPercentageChanged result = RNSvgaPlayerEventEmitter::OnPercentageChanged{RNSvgaPlayerEventEmitter::OnPercentageChanged( percentage )};
454
+ self.eventEmitter.onPercentageChanged(result);
455
+ //直接事件
456
+ // std::dynamic_pointer_cast<const RNSvgaPlayerEventEmitter>(_eventEmitter)
457
+ // ->onFrameChanged(RNSvgaPlayerEventEmitter::OnFrameChanged{.value=(float)percentage});
384
458
  }
385
459
 
386
460
  // SVGAPlayerDelegate methods
@@ -390,16 +464,13 @@ Class<RCTComponentViewProtocol> SvgaPlayerViewCls(void)
390
464
  if (!_svgaPlayer || player != _svgaPlayer) {
391
465
  return;
392
466
  }
393
-
394
467
  // 检查事件发送器是否还有效
395
- if (_eventEmitter == nullptr) {
396
- return;
397
- }
398
-
399
- std::dynamic_pointer_cast<const facebook::react::RNSvgaPlayerEventEmitter>(_eventEmitter)
400
- ->onFinished(facebook::react::RNSvgaPlayerEventEmitter::OnFinished{
401
- .finished = true
402
- });
468
+ RNSvgaPlayerEventEmitter::OnFinished result = RNSvgaPlayerEventEmitter::OnFinished{RNSvgaPlayerEventEmitter::OnFinished( true )};
469
+ self.eventEmitter.onFinished(result);
470
+ // std::dynamic_pointer_cast<const facebook::react::RNSvgaPlayerEventEmitter>(_eventEmitter)
471
+ // ->onFinished(facebook::react::RNSvgaPlayerEventEmitter::OnFinished{
472
+ // .finished = true
473
+ // });
403
474
  }
404
475
 
405
476
  // React Native Fabric 生命周期方法
@@ -482,3 +553,4 @@ Class<RCTComponentViewProtocol> SvgaPlayerViewCls(void)
482
553
  }
483
554
 
484
555
  @end
556
+
package/package.json CHANGED
@@ -26,10 +26,10 @@
26
26
  "files": [
27
27
  "android",
28
28
  "ios",
29
- "rn-newarch-svga-player.podspec",
29
+ "lib",
30
30
  "src",
31
31
  "SvgaPlayer.tsx",
32
- "!node_modules/"
32
+ "rn-newarch-svga-player.podspec"
33
33
  ],
34
34
  "homepage": "https://github.com/yrjwcharm/rn-newarch-svga-player#readme",
35
35
  "keywords": [
@@ -53,5 +53,5 @@
53
53
  "scripts": {
54
54
  "codegen-lib": "react-native codegen-lib-harmony --no-safety-check --npm-package-name react-native-ohos-svgaplayer --cpp-output-path ../../harmony/svgaplayer/src/main/cpp/generated --ets-output-path ../../harmony/svgaplayer/src/main/ets/generated --turbo-modules-spec-paths ./src --arkts-components-spec-paths ./src"
55
55
  },
56
- "version": "1.1.4"
56
+ "version": "1.1.6"
57
57
  }
@@ -1,35 +1,60 @@
1
- import type {HostComponent, ViewProps} from 'react-native';
1
+ import type { HostComponent, ViewProps } from 'react-native';
2
2
  import type {
3
3
  BubblingEventHandler,
4
+ Double,
4
5
  Int32,
5
6
  WithDefault,
6
7
  } from 'react-native/Libraries/Types/CodegenTypes';
7
8
  import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
8
9
  import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
9
10
 
10
- interface NativeProps extends ViewProps {
11
- source?: string;
11
+ interface SvgaPlayerProps extends ViewProps {
12
+ source: string;
12
13
  autoPlay?: boolean;
13
14
  loops?: Int32;
14
15
  clearsAfterStop?: boolean;
15
16
  align?: WithDefault<'top' | 'bottom' | 'center', 'center'>;
16
-
17
17
  // 事件回调
18
- onError?: BubblingEventHandler<{error: string}>;
19
- onFinished?: BubblingEventHandler<{finished: boolean}>;
18
+ onError?: BubblingEventHandler<{ error: string }>;
19
+ onFinished?: BubblingEventHandler<{ finished: boolean }>;
20
20
  onLoaded?: BubblingEventHandler<{}>;
21
+ onFrameChanged?: BubblingEventHandler<{ value: Double }>;
22
+ onPercentageChanged?: BubblingEventHandler<{ value: Double }>;
21
23
  }
22
24
 
23
- export type ComponentType = HostComponent<NativeProps>;
25
+ export type ComponentType = HostComponent<SvgaPlayerProps>;
24
26
 
25
27
  interface NativeCommands {
26
28
  startAnimation: (viewRef: React.ElementRef<ComponentType>) => void;
27
- // pauseAnimation: (viewRef: React.ElementRef<ComponentType>) => void;
28
29
  stopAnimation: (viewRef: React.ElementRef<ComponentType>) => void;
30
+ pauseAnimation: (viewRef: React.ElementRef<ComponentType>) => void;
31
+ stepToFrame: (
32
+ viewRef: React.ElementRef<ComponentType>,
33
+ frame: Int32,
34
+ andPlay: boolean
35
+ ) => void;
36
+ stepToPercentage: (
37
+ viewRef: React.ElementRef<ComponentType>,
38
+ percentage: Int32,
39
+ andPlay: boolean
40
+ ) => void;
41
+ startAnimationWithRange: (
42
+ viewRef: React.ElementRef<ComponentType>,
43
+ location: Int32,
44
+ length: Int32,
45
+ reverse: boolean
46
+ ) => void;
29
47
  }
30
48
 
31
49
  export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
32
- supportedCommands: ['startAnimation', 'stopAnimation'],
50
+ supportedCommands: [
51
+ 'startAnimation',
52
+ 'pauseAnimation',
53
+ 'stopAnimation',
54
+ 'stepToFrame',
55
+ 'stepToPercentage',
56
+ 'startAnimationWithRange',
57
+ ],
33
58
  });
34
59
 
35
- export default codegenNativeComponent<NativeProps>('RNSvgaPlayer');
60
+ export default codegenNativeComponent<SvgaPlayerProps>('RNSvgaPlayer');
package/readme.md DELETED
@@ -1,184 +0,0 @@
1
- ## **_这是一款使用 ReactNative 加载`Android/iOS` Svga 动画的播放器插件_** [三端 Svga 动画统一使用点击这里](https://github.com/yrjwcharm/react-native-ohos/tree/feature/rnoh/svgaplayer)
2
-
3
- > ### 版本:latest
4
-
5
- <p align="center">
6
- <h1 align="center"> <code>rn-newarch-svga-player</code> </h1>
7
- </p>
8
- <p align="center">
9
- <a href="https://github.com/wonday/react-native-pdf/blob/master/LICENSE">
10
- <img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License" />
11
- </a>
12
- </p>
13
-
14
- > [!TIP] [Github 地址](https://github.com/yrjwcharm/rn-newarch-svga-player)
15
-
16
- ## 安装与使用
17
-
18
- > [!TIP] 注意 ⚠️ 本库 android/ios 仅给予 Fabric 新架构支持,旧架构不在跟进,若需旧架构支持请移步<https://github.com/yrjwcharm/react-native-svga-player>
19
-
20
- **确保你的 Android/iOS 已经开启了新架构支持 <https://reactnative.cn/docs/0.72/the-new-architecture/use-app-template>**
21
-
22
- #### **npm**
23
-
24
- ```bash
25
- npm install rn-newarch-svga-player
26
- ```
27
-
28
- #### **yarn**
29
-
30
- ```bash
31
- yarn add rn-newarch-svga-player
32
- ```
33
-
34
- > 若想更改库的别名 react-native-svga-player 来导入。你则需要把 rn-newarch-svga-player 库修改下,重新 yarn 执行
35
-
36
- ```diff
37
- + "dependencies": {
38
- "@react-native-oh/react-native-harmony": "0.72.48",
39
- "patch-package": "^8.0.0",
40
- "postinstall-postinstall": "^2.1.0",
41
- "react": "18.2.0",
42
- "react-native": "0.72.5",
43
- - "rn-newarch-svga-player":"^1.1.2"
44
- + "react-native-svga-player":"npm:rn-newarch-svga-player@1.1.2"
45
- },
46
- ```
47
- android 需要
48
-
49
- ```bash
50
- ./gradlew generateCodegenArtifactsFromSchema
51
- ```
52
-
53
- ios 需要
54
-
55
- ```bash
56
- cd ios
57
- bundle install && bundle exec pod install
58
- ```
59
-
60
- 下面的代码展示了这个库的基本使用场景:
61
-
62
- ```js
63
- import React, { useRef, useState } from "react";
64
- import {
65
- Button,
66
- SafeAreaView,
67
- ScrollView,
68
- StatusBar,
69
- StyleSheet,
70
- Text,
71
- View,
72
- } from "react-native";
73
- import { RNSvgaPlayer, SvgaPlayerRef } from "react-native-svga-player";
74
- const App = () => {
75
- const svgaPlayerRef = useRef < SvgaPlayerRef > null;
76
- //播放网络资源
77
- const [source, setSource] = useState(
78
- "https://raw.githubusercontent.com/yyued/SVGAPlayer-iOS/master/SVGAPlayer/Samples/Goddess.svga"
79
- );
80
- //播放本地资源
81
- // const [source, setSource] = useState(
82
- // 'homePage_studyPlanner_computer_welcome.svga',
83
- // );
84
- return (
85
- <SafeAreaView style={styles.container}>
86
- <StatusBar barStyle={"dark-content"} />
87
- <ScrollView showsVerticalScrollIndicator={false}>
88
- <Text style={styles.welcome}>Svga</Text>
89
- <RNSvgaPlayer
90
- ref={svgaPlayerRef}
91
- source={source}
92
- autoPlay={true}
93
- loops={1} // 循环次数,默认 0无限循环
94
- clearsAfterStop={false} // 停止后清空画布,默认 true
95
- style={styles.svgaStyle}
96
- onFinished={() => {
97
- console.log("播放完成");
98
- }} // 播放完成回调
99
- onLoaded={() => {
100
- console.log("动画加载完成");
101
- }}
102
- />
103
- <View style={styles.flexAround}>
104
- <Button
105
- title="开始动画"
106
- onPress={() => {
107
- svgaPlayerRef.current?.startAnimation();
108
- }}
109
- />
110
- <Button
111
- title="暂停动画"
112
- onPress={() => {
113
- // svgaPlayerRef.current?.pauseAnimation();
114
- }}
115
- />
116
- <Button
117
- title="停止动画"
118
- onPress={() => {
119
- svgaPlayerRef.current?.stopAnimation();
120
- }}
121
- />
122
- </View>
123
- <View style={[styles.flexAround, { marginTop: 20 }]}>
124
- <Button
125
- title="手动加载动画"
126
- onPress={() => {
127
- setSource(
128
- "https://raw.githubusercontent.com/yyued/SVGAPlayer-iOS/master/SVGAPlayer/Samples/matteBitmap.svga"
129
- );
130
- }}
131
- />
132
- <Button
133
- title="指定帧开始"
134
- onPress={() => {
135
- // svgaPlayerRef.current?.stepToFrame(20, true);
136
- }}
137
- />
138
- <Button
139
- title="指定百分比开始"
140
- onPress={() => {
141
- // svgaPlayerRef.current?.stepToPercentage(1, true);
142
- }}
143
- />
144
- </View>
145
- </ScrollView>
146
- </SafeAreaView>
147
- );
148
- };
149
- export default App;
150
- const styles = StyleSheet.create({
151
- flexAround: { flexDirection: "row", justifyContent: "space-around" },
152
- container: {
153
- flex: 1,
154
- },
155
- svgaStyle: {
156
- width: 150,
157
- height: 150,
158
- marginTop: 30,
159
- },
160
- welcome: {
161
- fontSize: 20,
162
- textAlign: "center",
163
- margin: 10,
164
- marginTop: 80,
165
- },
166
- instructions: {
167
- textAlign: "center",
168
- color: "#333333",
169
- marginBottom: 5,
170
- },
171
- });
172
- ```
173
-
174
- #### 新架构[Android/iOS]demo 请参考 <https://github.com/yrjwcharm/react-native-ohos/tree/feature/newarch/svgaplayer>
175
-
176
- 更多详情用法参考 [三端 Svga 动画统一使用点击这里](https://github.com/yrjwcharm/react-native-ohos/tree/feature/rnoh/svgaplayer)
177
-
178
- #### 开源不易,希望您可以动一动小手点点小 ⭐⭐
179
-
180
- #### 👴 希望大家如有好的需求踊跃提交,如有问题请提交 issue,空闲时间会扩充与修复优化
181
-
182
- ## 开源协议
183
-
184
- 本项目基于 [The MIT License (MIT)](https://github.com/yrjwcharm/react-native-ohos-svgaplayer/blob/master/LICENSE) ,请自由地享受和参与开源。