{
195 | ProtoAdapter_Transform() {
196 | super(FieldEncoding.LENGTH_DELIMITED, Transform.class);
197 | }
198 |
199 | @Override
200 | public int encodedSize(Transform value) {
201 | return (value.a != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(1, value.a) : 0)
202 | + (value.b != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(2, value.b) : 0)
203 | + (value.c != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(3, value.c) : 0)
204 | + (value.d != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(4, value.d) : 0)
205 | + (value.tx != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(5, value.tx) : 0)
206 | + (value.ty != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(6, value.ty) : 0)
207 | + value.unknownFields().size();
208 | }
209 |
210 | @Override
211 | public void encode(ProtoWriter writer, Transform value) throws IOException {
212 | if (value.a != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 1, value.a);
213 | if (value.b != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 2, value.b);
214 | if (value.c != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 3, value.c);
215 | if (value.d != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 4, value.d);
216 | if (value.tx != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 5, value.tx);
217 | if (value.ty != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 6, value.ty);
218 | writer.writeBytes(value.unknownFields());
219 | }
220 |
221 | @Override
222 | public Transform decode(ProtoReader reader) throws IOException {
223 | Builder builder = new Builder();
224 | long token = reader.beginMessage();
225 | for (int tag; (tag = reader.nextTag()) != -1;) {
226 | switch (tag) {
227 | case 1: builder.a(ProtoAdapter.FLOAT.decode(reader)); break;
228 | case 2: builder.b(ProtoAdapter.FLOAT.decode(reader)); break;
229 | case 3: builder.c(ProtoAdapter.FLOAT.decode(reader)); break;
230 | case 4: builder.d(ProtoAdapter.FLOAT.decode(reader)); break;
231 | case 5: builder.tx(ProtoAdapter.FLOAT.decode(reader)); break;
232 | case 6: builder.ty(ProtoAdapter.FLOAT.decode(reader)); break;
233 | default: {
234 | FieldEncoding fieldEncoding = reader.peekFieldEncoding();
235 | Object value = fieldEncoding.rawProtoAdapter().decode(reader);
236 | builder.addUnknownField(tag, fieldEncoding, value);
237 | }
238 | }
239 | }
240 | reader.endMessage(token);
241 | return builder.build();
242 | }
243 |
244 | @Override
245 | public Transform redact(Transform value) {
246 | Builder builder = value.newBuilder();
247 | builder.clearUnknownFields();
248 | return builder.build();
249 | }
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/library/src/main/java/com/opensource/svgaplayer/utils/Pools.kt:
--------------------------------------------------------------------------------
1 | package com.opensource.svgaplayer.utils
2 |
3 | /**
4 | * Helper class for creating pools of objects. An example use looks like this:
5 | *
6 | * public class MyPooledClass {
7 | *
8 | * private static final SynchronizedPool sPool =
9 | * new SynchronizedPool(10);
10 | *
11 | * public static MyPooledClass obtain() {
12 | * MyPooledClass instance = sPool.acquire();
13 | * return (instance != null) ? instance : new MyPooledClass();
14 | * }
15 | *
16 | * public void recycle() {
17 | * // Clear state if needed.
18 | * sPool.release(this);
19 | * }
20 | *
21 | * . . .
22 | * }
23 | *
24 | *
25 | */
26 | class Pools private constructor() {
27 |
28 | /**
29 | * Interface for managing a pool of objects.
30 | *
31 | * @param The pooled type.
32 | */
33 | interface Pool {
34 | /**
35 | * @return An instance from the pool if such, null otherwise.
36 | */
37 | fun acquire(): T?
38 |
39 | /**
40 | * Release an instance to the pool.
41 | *
42 | * @param instance The instance to release.
43 | * @return Whether the instance was put in the pool.
44 | *
45 | * @throws IllegalStateException If the instance is already in the pool.
46 | */
47 | fun release(instance: T): Boolean
48 | }
49 |
50 | /**
51 | * Simple (non-synchronized) pool of objects.
52 | *
53 | * @param maxPoolSize The max pool size.
54 | *
55 | * @throws IllegalArgumentException If the max pool size is less than zero.
56 | *
57 | * @param The pooled type.
58 | */
59 | open class SimplePool(maxPoolSize: Int) : Pool {
60 | private val mPool: Array
61 | private var mPoolSize = 0
62 |
63 | init {
64 | require(maxPoolSize > 0) { "The max pool size must be > 0" }
65 | mPool = arrayOfNulls(maxPoolSize)
66 | }
67 |
68 | @Suppress("UNCHECKED_CAST")
69 | override fun acquire(): T? {
70 | if (mPoolSize > 0) {
71 | val lastPooledIndex = mPoolSize - 1
72 | val instance = mPool[lastPooledIndex] as T?
73 | mPool[lastPooledIndex] = null
74 | mPoolSize--
75 | return instance
76 | }
77 | return null
78 | }
79 |
80 | override fun release(instance: T): Boolean {
81 | check(!isInPool(instance)) { "Already in the pool!" }
82 | if (mPoolSize < mPool.size) {
83 | mPool[mPoolSize] = instance
84 | mPoolSize++
85 | return true
86 | }
87 | return false
88 | }
89 |
90 | private fun isInPool(instance: T): Boolean {
91 | for (i in 0 until mPoolSize) {
92 | if (mPool[i] === instance) {
93 | return true
94 | }
95 | }
96 | return false
97 | }
98 |
99 | }
100 |
101 |
102 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/opensource/svgaplayer/utils/SVGAScaleInfo.kt:
--------------------------------------------------------------------------------
1 | package com.opensource.svgaplayer.utils
2 |
3 | import android.widget.ImageView
4 |
5 | /**
6 | * Created by ubt on 2018/1/19.
7 | */
8 | class SVGAScaleInfo {
9 |
10 | var tranFx : Float = 0.0f
11 | var tranFy : Float = 0.0f
12 | var scaleFx : Float = 1.0f
13 | var scaleFy : Float = 1.0f
14 | var ratio = 1.0f
15 | var ratioX = false
16 |
17 | private fun resetVar(){
18 | tranFx = 0.0f
19 | tranFy = 0.0f
20 | scaleFx = 1.0f
21 | scaleFy = 1.0f
22 | ratio = 1.0f
23 | ratioX = false
24 | }
25 |
26 | fun performScaleType(canvasWidth : Float, canvasHeight: Float, videoWidth : Float, videoHeight : Float, scaleType: ImageView.ScaleType) {
27 | if (canvasWidth == 0.0f || canvasHeight == 0.0f || videoWidth == 0.0f || videoHeight == 0.0f) {
28 | return
29 | }
30 |
31 | resetVar()
32 | val canW_vidW_f = (canvasWidth - videoWidth) / 2.0f
33 | val canH_vidH_f = (canvasHeight - videoHeight) / 2.0f
34 |
35 | val videoRatio = videoWidth / videoHeight
36 | val canvasRatio = canvasWidth / canvasHeight
37 |
38 | val canH_d_vidH = canvasHeight / videoHeight
39 | val canW_d_vidW = canvasWidth / videoWidth
40 |
41 | when (scaleType) {
42 | ImageView.ScaleType.CENTER -> {
43 | tranFx = canW_vidW_f
44 | tranFy = canH_vidH_f
45 | }
46 | ImageView.ScaleType.CENTER_CROP -> {
47 | if (videoRatio > canvasRatio) {
48 | ratio = canH_d_vidH
49 | ratioX = false
50 | scaleFx = canH_d_vidH
51 | scaleFy = canH_d_vidH
52 | tranFx = (canvasWidth - videoWidth * (canH_d_vidH)) / 2.0f
53 | }
54 | else {
55 | ratio = canW_d_vidW
56 | ratioX = true
57 | scaleFx = canW_d_vidW
58 | scaleFy = canW_d_vidW
59 | tranFy = (canvasHeight - videoHeight * (canW_d_vidW)) / 2.0f
60 | }
61 | }
62 | ImageView.ScaleType.CENTER_INSIDE -> {
63 | if (videoWidth < canvasWidth && videoHeight < canvasHeight) {
64 | tranFx = canW_vidW_f
65 | tranFy = canH_vidH_f
66 | }
67 | else {
68 | if (videoRatio > canvasRatio) {
69 | ratio = canW_d_vidW
70 | ratioX = true
71 | scaleFx = canW_d_vidW
72 | scaleFy = canW_d_vidW
73 | tranFy = (canvasHeight - videoHeight * (canW_d_vidW)) / 2.0f
74 |
75 | }
76 | else {
77 | ratio = canH_d_vidH
78 | ratioX = false
79 | scaleFx = canH_d_vidH
80 | scaleFy = canH_d_vidH
81 | tranFx = (canvasWidth - videoWidth * (canH_d_vidH)) / 2.0f
82 | }
83 | }
84 | }
85 | ImageView.ScaleType.FIT_CENTER -> {
86 | if (videoRatio > canvasRatio) {
87 | ratio = canW_d_vidW
88 | ratioX = true
89 | scaleFx = canW_d_vidW
90 | scaleFy = canW_d_vidW
91 | tranFy = (canvasHeight - videoHeight * (canW_d_vidW)) / 2.0f
92 | }
93 | else {
94 | ratio = canH_d_vidH
95 | ratioX = false
96 | scaleFx = canH_d_vidH
97 | scaleFy = canH_d_vidH
98 | tranFx = (canvasWidth - videoWidth * (canH_d_vidH)) / 2.0f
99 | }
100 | }
101 | ImageView.ScaleType.FIT_START -> {
102 | if (videoRatio > canvasRatio) {
103 | ratio = canW_d_vidW
104 | ratioX = true
105 | scaleFx = canW_d_vidW
106 | scaleFy = canW_d_vidW
107 | }
108 | else {
109 | ratio = canH_d_vidH
110 | ratioX = false
111 | scaleFx = canH_d_vidH
112 | scaleFy = canH_d_vidH
113 | }
114 | }
115 | ImageView.ScaleType.FIT_END -> {
116 | if (videoRatio > canvasRatio) {
117 | ratio = canW_d_vidW
118 | ratioX = true
119 | scaleFx = canW_d_vidW
120 | scaleFy = canW_d_vidW
121 | tranFy= canvasHeight - videoHeight * (canW_d_vidW)
122 | }
123 | else {
124 | ratio = canH_d_vidH
125 | ratioX = false
126 | scaleFx = canH_d_vidH
127 | scaleFy = canH_d_vidH
128 | tranFx = canvasWidth - videoWidth * (canH_d_vidH)
129 | }
130 | }
131 | ImageView.ScaleType.FIT_XY -> {
132 | ratio = Math.max(canW_d_vidW, canH_d_vidH)
133 | ratioX = canW_d_vidW > canH_d_vidH
134 | scaleFx = canW_d_vidW
135 | scaleFy = canH_d_vidH
136 | }
137 | else -> {
138 | ratio = canW_d_vidW
139 | ratioX = true
140 | scaleFx = canW_d_vidW
141 | scaleFy = canW_d_vidW
142 | }
143 | }
144 | }
145 |
146 | }
147 |
--------------------------------------------------------------------------------
/library/src/main/java/com/opensource/svgaplayer/utils/SVGAStructs.kt:
--------------------------------------------------------------------------------
1 | package com.opensource.svgaplayer.utils
2 |
3 | /**
4 | * Created by cuiminghui on 2017/3/29.
5 | */
6 |
7 | class SVGAPoint(val x: Float, val y: Float, val value: Float)
8 |
9 | class SVGARect(val x: Double, val y: Double, val width: Double, val height: Double)
10 |
11 | class SVGARange(val location: Int, val length: Int)
--------------------------------------------------------------------------------
/library/src/main/java/com/opensource/svgaplayer/utils/log/DefaultLogCat.kt:
--------------------------------------------------------------------------------
1 | package com.opensource.svgaplayer.utils.log
2 |
3 | import android.util.Log
4 |
5 | /**
6 | * 内部默认 ILogger 接口实现
7 | */
8 | class DefaultLogCat : ILogger {
9 | override fun verbose(tag: String, msg: String) {
10 | Log.v(tag, msg)
11 | }
12 |
13 | override fun info(tag: String, msg: String) {
14 | Log.i(tag, msg)
15 | }
16 |
17 | override fun debug(tag: String, msg: String) {
18 | Log.d(tag, msg)
19 | }
20 |
21 | override fun warn(tag: String, msg: String) {
22 | Log.w(tag, msg)
23 | }
24 |
25 | override fun error(tag: String, msg: String?, error: Throwable?) {
26 | Log.e(tag, msg, error)
27 | }
28 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/opensource/svgaplayer/utils/log/ILogger.kt:
--------------------------------------------------------------------------------
1 | package com.opensource.svgaplayer.utils.log
2 |
3 | /**
4 | * log 外部接管接口
5 | **/
6 | interface ILogger {
7 | fun verbose(tag: String, msg: String)
8 | fun info(tag: String, msg: String)
9 | fun debug(tag: String, msg: String)
10 | fun warn(tag: String, msg: String)
11 | fun error(tag: String, msg: String?, error: Throwable?)
12 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/opensource/svgaplayer/utils/log/LogUtils.kt:
--------------------------------------------------------------------------------
1 | package com.opensource.svgaplayer.utils.log
2 |
3 | /**
4 | * 日志输出
5 | */
6 | internal object LogUtils {
7 | private const val TAG = "SVGALog"
8 |
9 | fun verbose(tag: String = TAG, msg: String) {
10 | if (!SVGALogger.isLogEnabled()) {
11 | return
12 | }
13 | SVGALogger.getSVGALogger()?.verbose(tag, msg)
14 | }
15 |
16 | fun info(tag: String = TAG, msg: String) {
17 | if (!SVGALogger.isLogEnabled()) {
18 | return
19 | }
20 | SVGALogger.getSVGALogger()?.info(tag, msg)
21 | }
22 |
23 | fun debug(tag: String = TAG, msg: String) {
24 | if (!SVGALogger.isLogEnabled()) {
25 | return
26 | }
27 | SVGALogger.getSVGALogger()?.debug(tag, msg)
28 | }
29 |
30 | fun warn(tag: String = TAG, msg: String) {
31 | if (!SVGALogger.isLogEnabled()) {
32 | return
33 | }
34 | SVGALogger.getSVGALogger()?.warn(tag, msg)
35 | }
36 |
37 | fun error(tag: String = TAG, msg: String) {
38 | if (!SVGALogger.isLogEnabled()) {
39 | return
40 | }
41 | SVGALogger.getSVGALogger()?.error(tag, msg, null)
42 | }
43 |
44 | fun error(tag: String, error: Throwable) {
45 | if (!SVGALogger.isLogEnabled()) {
46 | return
47 | }
48 | SVGALogger.getSVGALogger()?.error(tag, error.message, error)
49 | }
50 |
51 | fun error(tag: String = TAG, msg: String, error: Throwable) {
52 | if (!SVGALogger.isLogEnabled()) {
53 | return
54 | }
55 | SVGALogger.getSVGALogger()?.error(tag, msg, error)
56 | }
57 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/opensource/svgaplayer/utils/log/SVGALogger.kt:
--------------------------------------------------------------------------------
1 | package com.opensource.svgaplayer.utils.log
2 |
3 | /**
4 | * SVGA logger 配置管理
5 | **/
6 | object SVGALogger {
7 |
8 | private var mLogger: ILogger? = DefaultLogCat()
9 | private var isLogEnabled = false
10 |
11 | /**
12 | * log 接管注入
13 | */
14 | fun injectSVGALoggerImp(logImp: ILogger): SVGALogger {
15 | mLogger = logImp
16 | return this
17 | }
18 |
19 | /**
20 | * 设置是否开启 log
21 | */
22 | fun setLogEnabled(isEnabled: Boolean): SVGALogger {
23 | isLogEnabled = isEnabled
24 | return this
25 | }
26 |
27 | /**
28 | * 获取当前 ILogger 实现类
29 | */
30 | fun getSVGALogger(): ILogger? {
31 | return mLogger
32 | }
33 |
34 | /**
35 | * 是否开启 log
36 | */
37 | fun isLogEnabled(): Boolean {
38 | return isLogEnabled
39 | }
40 | }
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SVGAPlayer
3 |
4 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Archived
2 | 本仓库已经停止维护,你仍然继续阅读源码及创建分叉,但本仓库不会继续更新,也不会回答任何 issue。
3 |
4 | This repo has stopped maintenance, you can still continue to read the source code and create forks, but this repo will not continue to be updated, nor will it answer any issues.
5 |
6 | # SVGAPlayer
7 |
8 | [简体中文](./readme.zh.md)
9 |
10 | ## 支持本项目
11 |
12 | 1. 轻点 GitHub Star,让更多人看到该项目。
13 |
14 | ## Introduce
15 |
16 | SVGAPlayer is a light-weight animation renderer. You use [tools](http://svga.io/designer.html) to export `svga` file from `Adobe Animate CC` or `Adobe After Effects`, and then use SVGAPlayer to render animation on mobile application.
17 |
18 | `SVGAPlayer-Android` render animation natively via Android Canvas Library, brings you a high-performance, low-cost animation experience.
19 |
20 | If wonder more information, go to this [website](http://svga.io/).
21 |
22 | ## Usage
23 |
24 | Here introduce `SVGAPlayer-Android` usage. Wonder exporting usage? Click [here](http://svga.io/designer.html).
25 |
26 | ### Install Via Gradle
27 |
28 | We host aar file on JitPack, your need to add `JitPack.io` repo `build.gradle`
29 |
30 | ```
31 | allprojects {
32 | repositories {
33 | ...
34 | maven { url 'https://jitpack.io' }
35 | }
36 | }
37 | ```
38 |
39 | Then, add dependency to app `build.gradle`.
40 |
41 | ```
42 | compile 'com.github.yyued:SVGAPlayer-Android:latest'
43 | ```
44 |
45 | [](https://jitpack.io/#yyued/SVGAPlayer-Android)
46 |
47 | ### Static Parser Support
48 | Perser#shareParser should be init(context) in Application or other Activity.
49 | Otherwise it will report an error:
50 | `Log.e("SVGAParser", "在配置 SVGAParser context 前, 无法解析 SVGA 文件。")`
51 |
52 |
53 | ### Matte Support
54 | Head on over to [Dynamic · Matte Layer](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-%C2%B7-Matte-Layer)
55 |
56 | ### Proguard-rules
57 |
58 | ```
59 | -keep class com.squareup.wire.** { *; }
60 | -keep class com.opensource.svgaplayer.proto.** { *; }
61 | ```
62 |
63 | ### Locate files
64 |
65 | SVGAPlayer could load svga file from Android `assets` directory or remote server.
66 |
67 | ### Using XML
68 |
69 | You may use `layout.xml` to add a `SVGAImageView`.
70 |
71 | ```xml
72 |
73 |
78 |
79 |
85 |
86 |
87 | ```
88 |
89 | The following attributes is allowable:
90 |
91 | #### source: String
92 |
93 | The svga file path, provide a path relative to Android assets directory, or provide a http url.
94 |
95 | #### autoPlay: Boolean
96 |
97 | Defaults to `true`.
98 |
99 | After animation parsed, plays animation automatically.
100 |
101 | #### loopCount: Int
102 |
103 | Defaults to `0`.
104 |
105 | How many times should animation loops. `0` means Infinity Loop.
106 |
107 | #### ~~clearsAfterStop: Boolean~~
108 |
109 | Defaults to `false`.When the animation is finished, whether to clear the canvas and the internal data of SVGAVideoEntity.
110 | It is no longer recommended. Developers can control resource release through clearAfterDetached, or manually control resource release through SVGAVideoEntity#clear
111 |
112 | #### clearsAfterDetached: Boolean
113 |
114 | Defaults to `false`.Clears canvas and the internal data of SVGAVideoEntity after SVGAImageView detached.
115 |
116 | #### fillMode: String
117 |
118 | Defaults to `Forward`. Could be `Forward`, `Backward`, `Clear`.
119 |
120 | `Forward` means animation will pause on last frame after finished.
121 |
122 | `Backward` means animation will pause on first frame after finished.
123 |
124 | `Clear` after the animation is played, all the canvas content is cleared, but it is only the canvas and does not involve the internal data of SVGAVideoEntity.
125 |
126 | ### Using code
127 |
128 | You may use code to add `SVGAImageView` either.
129 |
130 | #### Create a `SVGAImageView` instance.
131 |
132 | ```kotlin
133 | SVGAImageView imageView = new SVGAImageView(this);
134 | ```
135 |
136 | #### Declare a static Parser instance.
137 |
138 | ```kotlin
139 | parser = SVGAParser.shareParser()
140 | ```
141 |
142 | #### Init parser instance
143 |
144 | You should initialize the parser instance with context before usage.
145 | ```
146 | SVGAParser.shareParser().init(this);
147 | ```
148 |
149 | Otherwise it will report an error:
150 | `Log.e("SVGAParser", "在配置 SVGAParser context 前, 无法解析 SVGA 文件。")`
151 |
152 | You can also create `SVGAParser` instance by yourself.
153 |
154 | #### Create a `SVGAParser` instance, parse from assets like this.
155 |
156 | ```kotlin
157 | parser = new SVGAParser(this);
158 | // The third parameter is a default parameter, which is null by default. If this method is set, the audio parsing and playback will not be processed internally. The audio File instance will be sent back to the developer through PlayCallback, and the developer will control the audio playback and playback. stop
159 | parser.decodeFromAssets("posche.svga", object : SVGAParser.ParseCompletion {
160 | // ...
161 | }, object : SVGAParser.PlayCallback {
162 | // The default is null, can not be set
163 | })
164 | ```
165 |
166 | #### Create a `SVGAParser` instance, parse from remote server like this.
167 |
168 | ```kotlin
169 | parser = new SVGAParser(this);
170 | // The third parameter is a default parameter, which is null by default. If this method is set, the audio parsing and playback will not be processed internally. The audio File instance will be sent back to the developer through PlayCallback, and the developer will control the audio playback and playback. stop
171 | parser.decodeFromURL(new URL("https://github.com/yyued/SVGA-Samples/blob/master/posche.svga?raw=true"), new SVGAParser.ParseCompletion() {
172 | // ...
173 | }, object : SVGAParser.PlayCallback {
174 | // The default is null, can not be set
175 | })
176 | ```
177 |
178 | #### Create a `SVGADrawable` instance then set to `SVGAImageView`, play it as you want.
179 |
180 | ```kotlin
181 | parser = new SVGAParser(this);
182 | parser.decodeFromURL(..., new SVGAParser.ParseCompletion() {
183 | @Override
184 | public void onComplete(@NotNull SVGAVideoEntity videoItem) {
185 | SVGADrawable drawable = new SVGADrawable(videoItem);
186 | imageView.setImageDrawable(drawable);
187 | imageView.startAnimation();
188 | }
189 | @Override
190 | public void onError() {
191 |
192 | }
193 | });
194 | ```
195 |
196 | ### Cache
197 |
198 | `SVGAParser` will not manage any cache, you need to setup cacher by yourself.
199 |
200 | #### Setup HttpResponseCache
201 |
202 | `SVGAParser` depends on `URLConnection`, `URLConnection` uses `HttpResponseCache` to cache things.
203 |
204 | Add codes to `Application.java:onCreate` to setup cacher.
205 |
206 | ```kotlin
207 | val cacheDir = File(context.applicationContext.cacheDir, "http")
208 | HttpResponseCache.install(cacheDir, 1024 * 1024 * 128)
209 | ```
210 |
211 | ### SVGALogger
212 | Updated the internal log output, which can be managed and controlled through SVGALogger. It is not activated by default. Developers can also implement the ILogger interface to capture and collect logs externally to facilitate troubleshooting
213 | Set whether the log is enabled through the `setLogEnabled` method
214 | Inject a custom ILogger implementation class through the `injectSVGALoggerImp` method
215 |
216 |
217 | ```kotlin
218 |
219 | // By default, SVGA will not output any log, so you need to manually set it to true
220 | SVGALogger.setLogEnabled(true)
221 |
222 | // If you want to collect the output log of SVGA, you can obtain it in the following way
223 | SVGALogger.injectSVGALoggerImp(object: ILogger {
224 | // Implement related interfaces to receive log
225 | })
226 | ```
227 |
228 | ### SVGASoundManager
229 | Added SVGASoundManager to control SVGA audio, you need to manually call the init method to initialize, otherwise follow the default audio loading logic.
230 | In addition, through SVGASoundManager#setVolume, you can control the volume of SVGA playback. The range is [0f, 1f]. By default, the volume of all SVGA playbacks is controlled.
231 | And this method can set a second default parameter: SVGAVideoEntity, which means that only the current SVGA volume is controlled, and the volume of other SVGAs remains unchanged.
232 |
233 | ```kotlin
234 | // Initialize the audio manager for easy management of audio playback
235 | // If it is not initialized, the audio will be loaded in the original way by default
236 | SVGASoundManager.init()
237 |
238 | // Release audio resources
239 | SVGASoundManager.release()
240 |
241 | /**
242 | * Set the volume level, entity is null by default
243 | * When entity is null, it controls the volume of all audio loaded through SVGASoundManager, which includes the currently playing audio and subsequent loaded audio
244 | * When entity is not null, only the SVGA audio volume of the instance is controlled, and the others are not affected
245 | *
246 | * @param volume The value range is [0f, 1f]
247 | * @param entity That is, the instance of SVGAParser callback
248 | */
249 | SVGASoundManager.setVolume(volume, entity)
250 | ```
251 |
252 | ## Features
253 |
254 | Here are many feature samples.
255 |
256 | * [Replace an element with Bitmap.](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-Image)
257 | * [Add text above an element.](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-Text)
258 | * [Add static layout text above an element.](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-Text-Layout)
259 | * [Hides an element dynamicaly.](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-Hidden)
260 | * [Use a custom drawer for element.](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-Drawer)
261 |
262 | ## APIs
263 |
264 | Head on over to [https://github.com/yyued/SVGAPlayer-Android/wiki/APIs](https://github.com/yyued/SVGAPlayer-Android/wiki/APIs)
265 |
266 | ## CHANGELOG
267 |
268 | Head on over to [CHANGELOG](./CHANGELOG.md)
269 |
270 | ## Credits
271 |
272 | ### Contributors
273 |
274 | This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
275 |
276 |
277 |
278 | ### Backers
279 |
280 | Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/SVGAPlayer-Android#backer)]
281 |
282 |
283 |
284 | ### Sponsors
285 |
286 | Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/SVGAPlayer-Android#sponsor)]
287 |
288 |
289 |
290 |
--------------------------------------------------------------------------------
/readme.zh.md:
--------------------------------------------------------------------------------
1 | # SVGAPlayer
2 |
3 | ## 介绍
4 |
5 | `SVGAPlayer` 是一个轻量的动画渲染库。你可以使用[工具](http://svga.io/designer.html)从 `Adobe Animate CC` 或者 `Adobe After Effects` 中导出动画文件,然后使用 `SVGAPlayer` 在移动设备上渲染并播放。
6 |
7 | `SVGAPlayer-Android` 使用原生 Android Canvas 库渲染动画,为你提供高性能、低开销的动画体验。
8 |
9 | 如果你想要了解更多细节,请访问[官方网站](http://svga.io/)。
10 |
11 | ## 用法
12 |
13 | 我们在这里介绍 `SVGAPlayer-Android` 的用法。想要知道如何导出动画,点击[这里](http://svga.io/designer.html)。
14 |
15 | ### 使用 Gradle 安装
16 |
17 | 我们的 aar 包托管在 JitPack 上,你需要将 `JitPack.io` 仓库添加到工程 `build.gradle` 中。
18 |
19 | ```
20 | allprojects {
21 | repositories {
22 | ...
23 | maven { url 'https://jitpack.io' }
24 | }
25 | }
26 | ```
27 |
28 | 然后,在应用 `build.gradle` 中添加依赖。
29 |
30 | ```
31 | compile 'com.github.yyued:SVGAPlayer-Android:latest'
32 | ```
33 |
34 | [](https://jitpack.io/#yyued/SVGAPlayer-Android)
35 |
36 | ### Parser 单例支持
37 | SVGAParser 单例需要在使用之前初始化,
38 | 否则会上报错误信息:
39 | `Log.e("SVGAParser", "在配置 SVGAParser context 前, 无法解析 SVGA 文件。")`
40 |
41 |
42 | ### 遮罩支持
43 | 请参阅此处 [Dynamic · Matte Layer](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-%C2%B7-Matte-Layer)
44 |
45 | ### 混淆规则
46 |
47 | ```
48 | -keep class com.squareup.wire.** { *; }
49 | -keep class com.opensource.svgaplayer.proto.** { *; }
50 | ```
51 |
52 | ### 放置 svga 文件
53 |
54 | SVGAPlayer 可以从本地 `assets` 目录,或者远端服务器上加载动画文件。
55 |
56 | ### 使用 XML
57 |
58 | 你可以使用 `layout.xml` 添加一个 `SVGAImageView`。
59 |
60 | ```xml
61 |
62 |
67 |
68 |
74 |
75 |
76 | ```
77 |
78 | 在 XML 中,允许定义以下这些标签:
79 |
80 | #### source: String
81 | 用于表示 svga 文件的路径,提供一个在 `assets` 目录下的文件名,或者提供一个 http url 地址。
82 |
83 | #### autoPlay: Boolean
84 | 默认为 `true`,当动画加载完成后,自动播放。
85 |
86 | #### loopCount: Int
87 | 默认为 `0`,设置动画的循环次数,0 表示无限循环。
88 |
89 | #### ~~clearsAfterStop: Boolean~~
90 | 默认为 `false`,当动画播放完成后,是否清空画布,以及 SVGAVideoEntity 内部数据。
91 | 不再推荐使用,开发者可以通过 clearAfterDetached 控制资源释放,或者手动通过 SVGAVideoEntity#clear 控制资源释放
92 |
93 | #### clearsAfterDetached: Boolean
94 | 默认为 `false`,当 SVGAImageView 触发 onDetachedFromWindow 方法时,是否清空画布。
95 |
96 | #### fillMode: String
97 |
98 | 默认为 `Forward`,可以是 `Forward`、 `Backward`、 `Clear`。
99 |
100 | `Forward` 表示动画结束后,将停留在最后一帧。
101 |
102 | `Backward` 表示动画结束后,将停留在第一帧。
103 |
104 | `Clear` 表示动画播放完后,清空所有画布内容,但仅仅是画布,不涉及 SVGAVideoEntity 内部数据。
105 |
106 | ### 使用代码
107 |
108 | 也可以使用代码添加 `SVGAImageView`。
109 |
110 | #### 创建一个 `SVGAImageView` 实例
111 |
112 | ```kotlin
113 | SVGAImageView imageView = new SVGAImageView(this);
114 | ```
115 |
116 | #### 声明一个 `SVGAParser` 单例.
117 |
118 | ```kotlin
119 | parser = SVGAParser.shareParser()
120 | ```
121 |
122 | #### 初始化 `SVGAParser` 单例
123 |
124 | 必须在使用 `SVGAParser` 单例前初始化,
125 | ```
126 | SVGAParser.shareParser().init(this);
127 | ```
128 |
129 | 否则会上报错误信息:
130 | `Log.e("SVGAParser", "在配置 SVGAParser context 前, 无法解析 SVGA 文件。")`
131 |
132 | 你也可以自行创建 `SVGAParser` 实例。
133 |
134 | #### 创建一个 `SVGAParser` 实例,加载 assets 中的动画。
135 |
136 | ```kotlin
137 | parser = new SVGAParser(this);
138 | // 第三个为可缺省参数,默认为 null,如果设置该方法,则内部不在处理音频的解析以及播放,会通过 PlayCallback 把音频 File 实例回传给开发者,有开发者自行控制音频的播放与停止。
139 | parser.decodeFromAssets("posche.svga", object : SVGAParser.ParseCompletion {
140 | // ...
141 | }, object : SVGAParser.PlayCallback {
142 | // The default is null, can not be set
143 | })
144 | ```
145 |
146 | #### 创建一个 `SVGAParser` 实例,加载远端服务器中的动画。
147 |
148 | ```kotlin
149 | parser = new SVGAParser(this);
150 | // 第三个为可缺省参数,默认为 null,如果设置该方法,则内部不在处理音频的解析以及播放,会通过 PlayCallback 把音频 File 实例回传给开发者,有开发者自行控制音频的播放与停止。
151 | parser.decodeFromURL(new URL("https://github.com/yyued/SVGA-Samples/blob/master/posche.svga?raw=true"), new SVGAParser.ParseCompletion() {
152 | // ...
153 | }, object : SVGAParser.PlayCallback {
154 | // The default is null, can not be set
155 | })
156 | ```
157 |
158 | #### 创建一个 `SVGADrawable` 实例,并赋值给 `SVGAImageView`,然后播放动画。
159 |
160 | ```kotlin
161 | parser = new SVGAParser(this);
162 | parser.decodeFromURL(..., new SVGAParser.ParseCompletion() {
163 | @Override
164 | public void onComplete(@NotNull SVGAVideoEntity videoItem) {
165 | SVGADrawable drawable = new SVGADrawable(videoItem);
166 | imageView.setImageDrawable(drawable);
167 | imageView.startAnimation();
168 | }
169 | @Override
170 | public void onError() {
171 |
172 | }
173 | });
174 | ```
175 |
176 | ### 缓存
177 |
178 | `SVGAParser` 不会管理缓存,你需要自行实现缓存器。
179 |
180 | #### 设置 HttpResponseCache
181 |
182 | `SVGAParser` 依赖 `URLConnection`, `URLConnection` 使用 `HttpResponseCache` 处理缓存。
183 |
184 | 添加代码至 `Application.java:onCreate` 以设置缓存。
185 |
186 | ```kotlin
187 | val cacheDir = File(context.applicationContext.cacheDir, "http")
188 | HttpResponseCache.install(cacheDir, 1024 * 1024 * 128)
189 | ```
190 |
191 | ### SVGALogger
192 | 更新了内部 log 输出,可通过 SVGALogger 去管理和控制,默认是未启用 log 输出,开发者们也可以实现 ILogger 接口,做到外部捕获收集 log,方便排查问题。
193 | 通过 `setLogEnabled` 方法设置日志是否开启。
194 | 通过 `injectSVGALoggerImp` 方法注入自定义 ILogger 实现类。
195 |
196 | ```kotlin
197 |
198 | // 默认情况下,SVGA 内部不会输出任何 log,所以需要手动设置为 true
199 | SVGALogger.setLogEnabled(true)
200 |
201 | // 如果希望收集 SVGA 内部输出的日志,则可通过下面方式获取
202 | SVGALogger.injectSVGALoggerImp(object: ILogger {
203 | // 实现相关接口进行接收 log
204 | })
205 | ```
206 |
207 | ### SVGASoundManager
208 | 新增 SVGASoundManager 控制 SVGA 音频,需要手动调用 init 方法进行初始化,否则按照默认的音频加载逻辑。
209 | 另外通过 SVGASoundManager#setVolume 可控制 SVGA 播放时的音量大小,范围值在 [0f, 1f],默认控制所有 SVGA 播放时的音量,
210 | 而且该方法可设置第二个可缺省参数:SVGAVideoEntity,表示仅控制当前 SVGA 的音量大小,其他 SVGA 的音量保持不变。
211 |
212 | ```kotlin
213 | // 初始化音频管理器,方便管理音频播放
214 | // 如果没有初始化,则默认按照原有方式加载音频
215 | SVGASoundManager.init()
216 |
217 | // 释放音频资源
218 | SVGASoundManager.release()
219 |
220 | /**
221 | * 设置音量大小,entity 默认为空
222 | * 当 entity 为空,则控制所有通过 SVGASoundManager 加载的音频音量大小,即包括当前正在播放的音频以及后续加载的音频
223 | * 当 entity 不为空,则仅控制该实例的 SVGA 音频音量大小,其他则不受影响
224 | *
225 | * @param volume 取值范围为 [0f, 1f]
226 | * @param entity 即 SVGAParser 回调回来的实例
227 | */
228 | SVGASoundManager.setVolume(volume, entity)
229 | ```
230 |
231 |
232 | ## 功能示例
233 |
234 | * [使用位图替换指定元素。](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-Image)
235 | * [在指定元素上绘制文本。](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-Text)
236 | * [在指定元素上绘制富文本。](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-Text-Layout)
237 | * [隐藏指定元素。](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-Hidden)
238 | * [在指定元素上自由绘制。](https://github.com/yyued/SVGAPlayer-Android/wiki/Dynamic-Drawer)
239 |
240 | ## APIs
241 |
242 | 请参阅此处 [https://github.com/yyued/SVGAPlayer-Android/wiki/APIs](https://github.com/yyued/SVGAPlayer-Android/wiki/APIs)
243 |
244 | ## CHANGELOG
245 |
246 | 请参阅此处 [CHANGELOG](./CHANGELOG.md)
247 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library'
2 |
--------------------------------------------------------------------------------