├── .gitignore
├── .idea
├── libraries
│ ├── Dart_SDK.xml
│ └── Flutter_for_Android.xml
├── modules.xml
├── runConfigurations
│ └── example_lib_main_dart.xml
└── workspace.xml
├── .metadata
├── .vscode
└── launch.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.zh.md
├── analysis_options.yaml
├── example
├── .gitignore
├── .metadata
├── README.md
├── android
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── opensource
│ │ │ │ │ └── svgaplayer_flutter_example
│ │ │ │ │ └── MainActivity.java
│ │ │ └── res
│ │ │ │ ├── drawable
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ └── values
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── assets
│ ├── angel.svga
│ └── pin_jump.svga
├── ios
│ ├── Flutter
│ │ ├── .last_build_id
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ ├── Flutter.podspec
│ │ ├── Release.xcconfig
│ │ └── flutter_export_environment.sh
│ ├── Podfile
│ ├── Podfile.lock
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── Runner
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── main.m
├── lib
│ └── main.dart
├── pubspec.lock
├── pubspec.yaml
├── test
│ └── widget_test.dart
└── web
│ └── index.html
├── lib
├── dynamic_entity.dart
├── painter.dart
├── parser.dart
├── player.dart
├── proto
│ ├── svga.pb.dart
│ ├── svga.pbenum.dart
│ ├── svga.pbjson.dart
│ └── svga.pbserver.dart
├── simple_player.dart
└── svgaplayer_flutter.dart
├── package.json
├── pubspec.lock
├── pubspec.yaml
├── svgaplayer_flutter.iml
└── test
└── svgaplayer_flutter_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 |
7 | build/
8 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_SDK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/libraries/Flutter_for_Android.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/example_lib_main_dart.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 8661d8aecd626f7f57ccbcb735553edc05a2e713
8 | channel: stable
9 |
10 | project_type: plugin
11 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // 使用 IntelliSense 了解相关属性。
3 | // 悬停以查看现有属性的描述。
4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Flutter",
9 | "request": "launch",
10 | "type": "dart",
11 | "program": "example/lib/main.dart"
12 | },
13 | {
14 | "name": "Flutter profile",
15 | "request": "launch",
16 | "type": "dart",
17 | "program": "example/lib/main.dart",
18 | "args": ["--profile"]
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | #### 2.2.0 (2022-11-24)
2 |
3 | * Update path-drawing version.
4 |
5 | #### 2.1.2 (2021-06-26)
6 |
7 | * Fix KEEP path parser issue.
8 |
9 | #### 2.1.1 (2021-06-15)
10 |
11 | * Fix path parse error.
12 |
13 | #### 2.1.0 (2021-06-11)
14 |
15 | * Add Flutter Web support.
16 | * Add dispose method to MovieEntity.
17 | * Add IgnorePointer to CustomPaint.
18 | * Fix path parse error.
19 |
20 | #### 2.0.0 (2021-05-29)
21 |
22 | * Release 2.0.0.
23 |
24 | #### 2.0.0-nullsafety.0 (2021-03-31)
25 |
26 | * Add null safety support.
27 | * Upgrade all dependencies.
28 |
29 | #### 1.2.0 (2021-03-02)
30 |
31 | * Remove native plugin.
32 | * Improve decoding images speed.
33 |
34 | #### 1.1.0 (2020-03-19)
35 |
36 | * 修复 bitmap 锯齿问题和 dynamicItem frame 问题
37 | * fix: Keep type shape error parsed.
38 |
39 | #### 1.0.1 (2019-11-27)
40 |
41 | * Fix an issue about setText.
42 |
43 | #### 1.0.0 (2019-11-19)
44 |
45 | * Use protobuf `^1.0.0`
46 |
47 | #### 0.1.1 (2019-09-12)
48 |
49 | ##### Chores
50 |
51 | * Lock protobuf version < 0.13.16, because 0.13.16 leads build fail.
52 |
53 | #### 0.1.0 (2019-07-26)
54 |
55 | ##### Feat
56 |
57 | * Add file option to SVGASimpleImage.
58 |
59 | #### 0.0.4 (2019-07-01)
60 |
61 | ##### Bug Fixes
62 |
63 | * Should not draw as groups for bitmap or shape, should draw as a sprite one by one.
64 |
65 | #### 0.0.3 (2019-07-01)
66 |
67 | ##### Chores
68 |
69 | * upgrade to 0.0.3 (3c40d8bf)
70 | * 0.0.2 released. (7a54b493)
71 |
72 | ##### Bug Fixes
73 |
74 | * https://github.com/yyued/SVGAPlayer-Flutter/issues/2 (3e8db072)
75 |
76 | #### 0.0.1 (2019-04-01)
77 |
78 | ##### New Features
79 |
80 | * Add zh readme. (ed4ceaf8)
81 | * Add assets to SVGASimpleImage. (34ffe14d)
82 | * Add decodeFromAssets method to parser. (e2746e62)
83 | * Add dynamicText dynamicHidden and dynamicDrawer. (0a0f7201)
84 | * Add SVGASimpleImage. (f6add286)
85 | * Add static url method to create Widget. (516d356b)
86 | * Add callbacks. (4fce439d)
87 | * Add path cache. fix: Miss shape transform. (f8104fb7)
88 | * Add shape render. (0c75cc32)
89 | * Add Parser, Player and Bitmap render. (99a1be72)
90 |
91 | ##### Other Changes
92 |
93 | * Update samples and doc. (a5d78c51)
94 |
95 | ##### Refactors
96 |
97 | * use AnimationController base animation. (ac210165)
98 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This repo developed by PonyCui, and PonyCui has the full permission to fix LICENSE.
2 |
3 | The "Anti 996" was added at 2019.07.24, if you use the commit before(include) a5bc735067196caa422257ebbf4218a3c5989b3b, you may not obey "Anti 996" License.
4 |
5 | Copyright (c) <2019>
6 |
7 | "Anti 996" License Version 1.0 (Draft)
8 |
9 | Permission is hereby granted to any individual or legal entity
10 | obtaining a copy of this licensed work (including the source code,
11 | documentation and/or related items, hereinafter collectively referred
12 | to as the "licensed work"), free of charge, to deal with the licensed
13 | work for any purpose, including without limitation, the rights to use,
14 | reproduce, modify, prepare derivative works of, distribute, publish
15 | and sublicense the licensed work, subject to the following conditions:
16 |
17 | 1. The individual or the legal entity must conspicuously display,
18 | without modification, this License and the notice on each redistributed
19 | or derivative copy of the Licensed Work.
20 |
21 | 2. The individual or the legal entity must strictly comply with all
22 | applicable laws, regulations, rules and standards of the jurisdiction
23 | relating to labor and employment where the individual is physically
24 | located or where the individual was born or naturalized; or where the
25 | legal entity is registered or is operating (whichever is stricter). In
26 | case that the jurisdiction has no such laws, regulations, rules and
27 | standards or its laws, regulations, rules and standards are
28 | unenforceable, the individual or the legal entity are required to
29 | comply with Core International Labor Standards.
30 |
31 | 3. The individual or the legal entity shall not induce, suggest or force
32 | its employee(s), whether full-time or part-time, or its independent
33 | contractor(s), in any methods, to agree in oral or written form, to
34 | directly or indirectly restrict, weaken or relinquish his or her
35 | rights or remedies under such laws, regulations, rules and standards
36 | relating to labor and employment as mentioned above, no matter whether
37 | such written or oral agreements are enforceable under the laws of the
38 | said jurisdiction, nor shall such individual or the legal entity
39 | limit, in any methods, the rights of its employee(s) or independent
40 | contractor(s) from reporting or complaining to the copyright holder or
41 | relevant authorities monitoring the compliance of the license about
42 | its violation(s) of the said license.
43 |
44 | THE LICENSED WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
45 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
46 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
47 | IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM,
48 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
49 | OTHERWISE, ARISING FROM, OUT OF OR IN ANY WAY CONNECTION WITH THE
50 | LICENSED WORK OR THE USE OR OTHER DEALINGS IN THE LICENSED WORK.
51 |
--------------------------------------------------------------------------------
/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-Flutter
7 |
8 | [简体中文](./README.zh.md)
9 |
10 | ## 支持本项目
11 |
12 | 如果 SVGA-Flutter 为您提供了便利与帮助,诚恳建议您通过以下方式支持作者、贡献者持续为该项目发电。
13 |
14 | 1. 轻点 GitHub Star,让更多人看到该项目。
15 | 2. 通过赞赏码(页面底部可见)的方式鼓励作者继续维护代码。
16 |
17 | 关注作者另外一个开源项目,[MPFlutter](https://mpflutter.com/),使用 Flutter 开发微信小程序。
18 |
19 | ## Introduce
20 |
21 | SVGAPlayer is a light-weight animation renderer. You use [tools](https://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.
22 |
23 | `SVGAPlayer-Flutter` render animation natively via Flutter CustomPainter, brings you a high-performance, low-cost animation experience.
24 |
25 | If wonder more information, go to this [website](https://svga.io/).
26 |
27 | * SVGAPlayer-Flutter supports 2.0 format only.
28 |
29 | ## Usage
30 |
31 | Here introduce `SVGAPlayer-Flutter` usage. Wonder exporting usage? Click [here](https://svga.io/designer.html).
32 |
33 | ### Add dependency
34 |
35 | ```
36 | dependencies:
37 | svgaplayer_flutter: ^2.0.0 #latest version
38 | ```
39 |
40 | ### Locate files
41 |
42 | SVGAPlayer could load svga file from Flutter local `assets` directory or remote server. Add file to pubspec.yaml by yourself.
43 |
44 | ### Super simple to use
45 |
46 | The simplest way to render an animation is to use `SVGASimpleImage` component.
47 |
48 | ```dart
49 | class MyWidget extends Widget {
50 |
51 | @override
52 | Widget build(BuildContext context) {
53 | return Container(
54 | child: SVGASimpleImage(
55 | resUrl: "https://github.com/yyued/SVGA-Samples/blob/master/angel.svga?raw=true"),
56 | );
57 | }
58 |
59 | }
60 | ```
61 |
62 | Animation will run repeatedly. If you wondering a stronger animation controls, use code.
63 |
64 | ### Code to use
65 |
66 | To control an animation rendering, you need to create a `SVGAAnimationController` instance just like Flutter regular animation. Assign to `SVGAImage`, load and decode resource using `SVGAParser`, and then do things as you want with `SVGAAnimationController`.
67 |
68 | ```dart
69 | import 'package:flutter/material.dart';
70 | import 'package:svgaplayer_flutter/svgaplayer_flutter.dart';
71 |
72 | void main() => runApp(MyApp());
73 |
74 | class MyApp extends StatefulWidget {
75 | @override
76 | _MyAppState createState() => _MyAppState();
77 | }
78 |
79 | class _MyAppState extends State with SingleTickerProviderStateMixin {
80 | SVGAAnimationController animationController;
81 |
82 | @override
83 | void initState() {
84 | this.animationController = SVGAAnimationController(vsync: this);
85 | this.loadAnimation();
86 | super.initState();
87 | }
88 |
89 | @override
90 | void dispose() {
91 | this.animationController.dispose();
92 | super.dispose();
93 | }
94 |
95 | void loadAnimation() async {
96 | final videoItem = await SVGAParser.shared.decodeFromURL(
97 | "https://github.com/yyued/SVGA-Samples/blob/master/angel.svga?raw=true");
98 | this.animationController.videoItem = videoItem;
99 | this
100 | .animationController
101 | .repeat() // Try to use .forward() .reverse()
102 | .whenComplete(() => this.animationController.videoItem = null);
103 | }
104 |
105 | @override
106 | Widget build(BuildContext context) {
107 | return Container(
108 | child: SVGAImage(this.animationController),
109 | );
110 | }
111 | }
112 | ```
113 |
114 | ### Reuse MovieEntity
115 |
116 | The `MovieEntity` will `dispose` after `AnimationController` dispose or `AnimationController::videoItem` reset.
117 |
118 | After dispose, the `MovieEntity` can not reused.
119 |
120 | If you eager to reuse the `MovieEntity`, assign `MovieEntity::autorelease` to false.
121 |
122 | ```dart
123 | final videoItem = await SVGAParser.shared.decodeFromURL(
124 | "https://github.com/yyued/SVGA-Samples/blob/master/angel.svga?raw=true");
125 | videoItem.autorelease = false;
126 | ```
127 |
128 | You need to call `MovieEntity::dispose()` method when no need to use.
129 |
130 | ### Cache
131 |
132 | We will not manage any caches, you need to use `dio` or other libraries to handle resource caches.
133 |
134 | Use `SVGAParser.decodeFromBytes` method to decode caching data.
135 |
136 | ## Features
137 |
138 | Here are many feature samples.
139 |
140 | * [Replace an element with Bitmap.](https://github.com/yyued/SVGAPlayer-Flutter/wiki/Dynamic-Image)
141 | * [Add text above an element.](https://github.com/yyued/SVGAPlayer-Flutter/wiki/Dynamic-Text)
142 | * [Hides an element dynamicaly.](https://github.com/yyued/SVGAPlayer-Flutter/wiki/Dynamic-Hidden)
143 | * [Use a custom drawer for element.](https://github.com/yyued/SVGAPlayer-Flutter/wiki/Dynamic-Drawer)
144 |
145 | ## License
146 |
147 | [](https://996.icu)
148 |
149 | [Anti 996](./LICENSE)
150 |
151 |
152 | ## 感谢或联系作者
153 |
154 | 
155 |
--------------------------------------------------------------------------------
/README.zh.md:
--------------------------------------------------------------------------------
1 | # SVGAPlayer-Flutter
2 |
3 | ## 介绍
4 |
5 | `SVGAPlayer` 是一个轻量的动画渲染库。你可以使用[工具](https://svga.io/designer.html)从 `Adobe Animate CC` 或者 `Adobe After Effects` 中导出动画文件,然后使用 `SVGAPlayer` 在移动设备上渲染并播放。
6 |
7 | `SVGAPlayer-Flutter` 通过 Flutter CustomPainter 原生渲染动画,为您带来高性能,低成本的动画体验。
8 |
9 | 如果你想要了解更多细节,请访问[官方网站](https://svga.io/)。
10 |
11 | * SVGAPlayer-Flutter 只支持 2.0 版本格式.
12 |
13 | ## 用法
14 |
15 | 我们在这里介绍 `SVGAPlayer-Flutter` 的用法。想要知道如何导出动画,点击[这里](https://svga.io/designer.html)。
16 |
17 | ### 添加依赖
18 |
19 | ```
20 | dependencies:
21 | svgaplayer_flutter: ^2.0.0 #latest version
22 | ```
23 |
24 | ### 放置 svga 文件
25 |
26 | SVGAPlayer 可以从本地 `assets` 目录,或者远端服务器上加载动画文件。
27 |
28 | ### 简易用法
29 |
30 | 使用 `SVGASimpleImage` 组件进行动画渲染是最简单的。
31 |
32 | ```dart
33 | class MyWidget extends Widget {
34 |
35 | @override
36 | Widget build(BuildContext context) {
37 | return Container(
38 | child: SVGASimpleImage(
39 | resUrl: "https://github.com/yyued/SVGA-Samples/blob/master/angel.svga?raw=true"),
40 | );
41 | }
42 |
43 | }
44 | ```
45 |
46 | 动画将会循环播放,如果你希望更直接地控制动画,可以使用代码方式。
47 |
48 | ### 使用代码
49 |
50 | 为了控制动画的渲染操作,你需要创建一个 `SVGAAnimationController` 实例,这和普通的 Flutter 动画并没有什么区别。将这个实例赋予 `SVGAImage`,使用 `SVGAParser` 加载并解码资源,然后使用 Controller 播放动画。
51 |
52 | ```dart
53 | import 'package:flutter/material.dart';
54 | import 'package:svgaplayer_flutter/svgaplayer_flutter.dart';
55 |
56 | void main() => runApp(MyApp());
57 |
58 | class MyApp extends StatefulWidget {
59 | @override
60 | _MyAppState createState() => _MyAppState();
61 | }
62 |
63 | class _MyAppState extends State with SingleTickerProviderStateMixin {
64 | SVGAAnimationController animationController;
65 |
66 | @override
67 | void initState() {
68 | this.animationController = SVGAAnimationController(vsync: this);
69 | this.loadAnimation();
70 | super.initState();
71 | }
72 |
73 | @override
74 | void dispose() {
75 | this.animationController.dispose();
76 | super.dispose();
77 | }
78 |
79 | void loadAnimation() async {
80 | final videoItem = await SVGAParser.shared.decodeFromURL(
81 | "https://github.com/yyued/SVGA-Samples/blob/master/angel.svga?raw=true");
82 | this.animationController.videoItem = videoItem;
83 | this
84 | .animationController
85 | .repeat() // Try to use .forward() .reverse()
86 | .whenComplete(() => this.animationController.videoItem = null);
87 | }
88 |
89 | @override
90 | Widget build(BuildContext context) {
91 | return Container(
92 | child: SVGAImage(this.animationController),
93 | );
94 | }
95 | }
96 | ```
97 |
98 | ### 复用 MovieEntity
99 |
100 | `MovieEntity` 对象会在 `AnimationController` dispose 调用后,或 `AnimationController::videoItem` 赋值后,执行 `dispose` 操作。
101 |
102 | 在 dispose 以后 `MovieEntity` 不可复用。
103 |
104 | 如果你需要复用 `MovieEntity` 对象,赋值 `MovieEntity::autorelease` 为 `false` 即可。
105 |
106 | ```dart
107 | final videoItem = await SVGAParser.shared.decodeFromURL(
108 | "https://github.com/yyued/SVGA-Samples/blob/master/angel.svga?raw=true");
109 | videoItem.autorelease = false;
110 | ```
111 |
112 | 当不再需要使用资源时,你需要自行调用 `MovieEntity::dispose()` 方法。
113 |
114 | ### 缓存
115 |
116 | 动画库不会管理任何缓存,你需要使用 `dio` 等网络库自行处理。
117 |
118 | 使用 `SVGAParser.decodeFromBytes` 方法解码数据。
119 |
120 | ## 功能示例
121 |
122 | * [使用位图替换指定元素。](https://github.com/yyued/SVGAPlayer-Flutter/wiki/Dynamic-Image)
123 | * [在指定元素上绘制文本。](https://github.com/yyued/SVGAPlayer-Flutter/wiki/Dynamic-Text)
124 | * [隐藏指定元素。](https://github.com/yyued/SVGAPlayer-Flutter/wiki/Dynamic-Hidden)
125 | * [在指定元素上自由绘制。](https://github.com/yyued/SVGAPlayer-Flutter/wiki/Dynamic-Drawer)
126 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # Visual Studio Code related
19 | .vscode/
20 |
21 | # Flutter/Dart/Pub related
22 | **/doc/api/
23 | .dart_tool/
24 | .flutter-plugins
25 | .packages
26 | .pub-cache/
27 | .pub/
28 | /build/
29 |
30 | # Android related
31 | **/android/**/gradle-wrapper.jar
32 | **/android/.gradle
33 | **/android/captures/
34 | **/android/gradlew
35 | **/android/gradlew.bat
36 | **/android/local.properties
37 | **/android/**/GeneratedPluginRegistrant.java
38 |
39 | # iOS/XCode related
40 | **/ios/**/*.mode1v3
41 | **/ios/**/*.mode2v3
42 | **/ios/**/*.moved-aside
43 | **/ios/**/*.pbxuser
44 | **/ios/**/*.perspectivev3
45 | **/ios/**/*sync/
46 | **/ios/**/.sconsign.dblite
47 | **/ios/**/.tags*
48 | **/ios/**/.vagrant/
49 | **/ios/**/DerivedData/
50 | **/ios/**/Icon?
51 | **/ios/**/Pods/
52 | **/ios/**/.symlinks/
53 | **/ios/**/profile
54 | **/ios/**/xcuserdata
55 | **/ios/.generated/
56 | **/ios/Flutter/App.framework
57 | **/ios/Flutter/Flutter.framework
58 | **/ios/Flutter/Generated.xcconfig
59 | **/ios/Flutter/app.flx
60 | **/ios/Flutter/app.zip
61 | **/ios/Flutter/flutter_assets/
62 | **/ios/ServiceDefinitions.json
63 | **/ios/Runner/GeneratedPluginRegistrant.*
64 |
65 | # Exceptions to above rules.
66 | !**/ios/**/default.mode1v3
67 | !**/ios/**/default.mode2v3
68 | !**/ios/**/default.pbxuser
69 | !**/ios/**/default.perspectivev3
70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
71 |
--------------------------------------------------------------------------------
/example/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 8661d8aecd626f7f57ccbcb735553edc05a2e713
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # svgaplayer_flutter_example
2 |
3 | Demonstrates how to use the svgaplayer_flutter plugin.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.io/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 31
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
36 | applicationId "com.opensource.svgaplayer_flutter_example"
37 | minSdkVersion 16
38 | targetSdkVersion 31
39 | versionCode flutterVersionCode.toInteger()
40 | versionName flutterVersionName
41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
42 | }
43 |
44 | buildTypes {
45 | release {
46 | // TODO: Add your own signing config for the release build.
47 | // Signing with the debug keys for now, so `flutter run --release` works.
48 | signingConfig signingConfigs.debug
49 | }
50 | }
51 | }
52 |
53 | flutter {
54 | source '../..'
55 | }
56 |
57 | dependencies {
58 | testImplementation 'junit:junit:4.12'
59 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
61 | }
62 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
12 |
20 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/opensource/svgaplayer_flutter_example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.opensource.svgaplayer_flutter_example;
2 |
3 | import android.os.Bundle;
4 |
5 | import io.flutter.embedding.android.FlutterActivity;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | }
9 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:7.0.4'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/example/assets/angel.svga:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/assets/angel.svga
--------------------------------------------------------------------------------
/example/assets/pin_jump.svga:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/assets/pin_jump.svga
--------------------------------------------------------------------------------
/example/ios/Flutter/.last_build_id:
--------------------------------------------------------------------------------
1 | 4d08af9c26259ca52b9e745a40cb7390
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Flutter.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # NOTE: This podspec is NOT to be published. It is only used as a local source!
3 | #
4 |
5 | Pod::Spec.new do |s|
6 | s.name = 'Flutter'
7 | s.version = '1.0.0'
8 | s.summary = 'High-performance, high-fidelity mobile apps.'
9 | s.description = <<-DESC
10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS.
11 | DESC
12 | s.homepage = 'https://flutter.io'
13 | s.license = { :type => 'MIT' }
14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
16 | s.ios.deployment_target = '8.0'
17 | s.vendored_frameworks = 'Flutter.framework'
18 | end
19 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/flutter_export_environment.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a generated file; do not edit or check into version control.
3 | export "FLUTTER_ROOT=/Users/saiakirahui/flutter"
4 | export "FLUTTER_APPLICATION_PATH=/Users/saiakirahui/Desktop/SVGAPlayer-Flutter/example"
5 | export "FLUTTER_TARGET=/Users/saiakirahui/Desktop/SVGAPlayer-Flutter/example/lib/main.dart"
6 | export "FLUTTER_BUILD_DIR=build"
7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios"
8 | export "FLUTTER_BUILD_NAME=1.0.0"
9 | export "FLUTTER_BUILD_NUMBER=1"
10 | export "DART_DEFINES=flutter.inspector.structuredErrors%3Dtrue"
11 | export "DART_OBFUSCATION=false"
12 | export "TRACK_WIDGET_CREATION=true"
13 | export "TREE_SHAKE_ICONS=false"
14 | export "PACKAGE_CONFIG=/Users/saiakirahui/Desktop/SVGAPlayer-Flutter/example/.dart_tool/package_config.json"
15 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def parse_KV_file(file, separator='=')
14 | file_abs_path = File.expand_path(file)
15 | if !File.exists? file_abs_path
16 | return [];
17 | end
18 | pods_ary = []
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) { |line|
21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22 | plugin = line.split(pattern=separator)
23 | if plugin.length == 2
24 | podname = plugin[0].strip()
25 | path = plugin[1].strip()
26 | podpath = File.expand_path("#{path}", file_abs_path)
27 | pods_ary.push({:name => podname, :path => podpath});
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | }
32 | return pods_ary
33 | end
34 |
35 | target 'Runner' do
36 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
37 | # referring to absolute paths on developers' machines.
38 | system('rm -rf .symlinks')
39 | system('mkdir -p .symlinks/plugins')
40 |
41 | # Flutter Pods
42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
43 | if generated_xcode_build_settings.empty?
44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
45 | end
46 | generated_xcode_build_settings.map { |p|
47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
48 | symlink = File.join('.symlinks', 'flutter')
49 | File.symlink(File.dirname(p[:path]), symlink)
50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
51 | end
52 | }
53 |
54 | # Plugin Pods
55 | plugin_pods = parse_KV_file('../.flutter-plugins')
56 | plugin_pods.map { |p|
57 | symlink = File.join('.symlinks', 'plugins', p[:name])
58 | File.symlink(p[:path], symlink)
59 | pod p[:name], :path => File.join(symlink, 'ios')
60 | }
61 | end
62 |
63 | post_install do |installer|
64 | installer.pods_project.targets.each do |target|
65 | target.build_configurations.each do |config|
66 | config.build_settings['ENABLE_BITCODE'] = 'NO'
67 | end
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/example/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODFILE CHECKSUM: aff02bfeed411c636180d6812254b2daeea14d09
2 |
3 | COCOAPODS: 1.9.1
4 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 1F157454912ACB0D29C33DA1 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C8BFA4B17CCA488F6519D4 /* libPods-Runner.a */; };
12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
13 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
14 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
15 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
16 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
17 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
18 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXCopyFilesBuildPhase section */
22 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
23 | isa = PBXCopyFilesBuildPhase;
24 | buildActionMask = 2147483647;
25 | dstPath = "";
26 | dstSubfolderSpec = 10;
27 | files = (
28 | );
29 | name = "Embed Frameworks";
30 | runOnlyForDeploymentPostprocessing = 0;
31 | };
32 | /* End PBXCopyFilesBuildPhase section */
33 |
34 | /* Begin PBXFileReference section */
35 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
36 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
37 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
38 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
39 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
40 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
41 | 805BF4801CDCB4C9520F8A1A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
42 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
43 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
44 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
45 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
46 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
47 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
48 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
49 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
50 | D0C8BFA4B17CCA488F6519D4 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
51 | E95B10158C67CBE172DE6F06 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
52 | F49FA3532CD7399F1325CA36 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
53 | /* End PBXFileReference section */
54 |
55 | /* Begin PBXFrameworksBuildPhase section */
56 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
57 | isa = PBXFrameworksBuildPhase;
58 | buildActionMask = 2147483647;
59 | files = (
60 | 1F157454912ACB0D29C33DA1 /* libPods-Runner.a in Frameworks */,
61 | );
62 | runOnlyForDeploymentPostprocessing = 0;
63 | };
64 | /* End PBXFrameworksBuildPhase section */
65 |
66 | /* Begin PBXGroup section */
67 | 1DFC42C9B7529C93C9E92E7D /* Pods */ = {
68 | isa = PBXGroup;
69 | children = (
70 | F49FA3532CD7399F1325CA36 /* Pods-Runner.debug.xcconfig */,
71 | 805BF4801CDCB4C9520F8A1A /* Pods-Runner.release.xcconfig */,
72 | E95B10158C67CBE172DE6F06 /* Pods-Runner.profile.xcconfig */,
73 | );
74 | name = Pods;
75 | sourceTree = "";
76 | };
77 | 6292D635F241CF4B91368F3C /* Frameworks */ = {
78 | isa = PBXGroup;
79 | children = (
80 | D0C8BFA4B17CCA488F6519D4 /* libPods-Runner.a */,
81 | );
82 | name = Frameworks;
83 | sourceTree = "";
84 | };
85 | 9740EEB11CF90186004384FC /* Flutter */ = {
86 | isa = PBXGroup;
87 | children = (
88 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
89 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
90 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
91 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
92 | );
93 | name = Flutter;
94 | sourceTree = "";
95 | };
96 | 97C146E51CF9000F007C117D = {
97 | isa = PBXGroup;
98 | children = (
99 | 9740EEB11CF90186004384FC /* Flutter */,
100 | 97C146F01CF9000F007C117D /* Runner */,
101 | 97C146EF1CF9000F007C117D /* Products */,
102 | 1DFC42C9B7529C93C9E92E7D /* Pods */,
103 | 6292D635F241CF4B91368F3C /* Frameworks */,
104 | );
105 | sourceTree = "";
106 | };
107 | 97C146EF1CF9000F007C117D /* Products */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 97C146EE1CF9000F007C117D /* Runner.app */,
111 | );
112 | name = Products;
113 | sourceTree = "";
114 | };
115 | 97C146F01CF9000F007C117D /* Runner */ = {
116 | isa = PBXGroup;
117 | children = (
118 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
119 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
120 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
121 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
122 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
123 | 97C147021CF9000F007C117D /* Info.plist */,
124 | 97C146F11CF9000F007C117D /* Supporting Files */,
125 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
126 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
127 | );
128 | path = Runner;
129 | sourceTree = "";
130 | };
131 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
132 | isa = PBXGroup;
133 | children = (
134 | 97C146F21CF9000F007C117D /* main.m */,
135 | );
136 | name = "Supporting Files";
137 | sourceTree = "";
138 | };
139 | /* End PBXGroup section */
140 |
141 | /* Begin PBXNativeTarget section */
142 | 97C146ED1CF9000F007C117D /* Runner */ = {
143 | isa = PBXNativeTarget;
144 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
145 | buildPhases = (
146 | F648A867F04CC1FB7002D25D /* [CP] Check Pods Manifest.lock */,
147 | 9740EEB61CF901F6004384FC /* Run Script */,
148 | 97C146EA1CF9000F007C117D /* Sources */,
149 | 97C146EB1CF9000F007C117D /* Frameworks */,
150 | 97C146EC1CF9000F007C117D /* Resources */,
151 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
152 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
153 | );
154 | buildRules = (
155 | );
156 | dependencies = (
157 | );
158 | name = Runner;
159 | productName = Runner;
160 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
161 | productType = "com.apple.product-type.application";
162 | };
163 | /* End PBXNativeTarget section */
164 |
165 | /* Begin PBXProject section */
166 | 97C146E61CF9000F007C117D /* Project object */ = {
167 | isa = PBXProject;
168 | attributes = {
169 | LastUpgradeCheck = 0910;
170 | ORGANIZATIONNAME = "The Chromium Authors";
171 | TargetAttributes = {
172 | 97C146ED1CF9000F007C117D = {
173 | CreatedOnToolsVersion = 7.3.1;
174 | DevelopmentTeam = 544P5CH38C;
175 | };
176 | };
177 | };
178 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
179 | compatibilityVersion = "Xcode 3.2";
180 | developmentRegion = English;
181 | hasScannedForEncodings = 0;
182 | knownRegions = (
183 | en,
184 | Base,
185 | );
186 | mainGroup = 97C146E51CF9000F007C117D;
187 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
188 | projectDirPath = "";
189 | projectRoot = "";
190 | targets = (
191 | 97C146ED1CF9000F007C117D /* Runner */,
192 | );
193 | };
194 | /* End PBXProject section */
195 |
196 | /* Begin PBXResourcesBuildPhase section */
197 | 97C146EC1CF9000F007C117D /* Resources */ = {
198 | isa = PBXResourcesBuildPhase;
199 | buildActionMask = 2147483647;
200 | files = (
201 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
202 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
203 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
204 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
205 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
206 | );
207 | runOnlyForDeploymentPostprocessing = 0;
208 | };
209 | /* End PBXResourcesBuildPhase section */
210 |
211 | /* Begin PBXShellScriptBuildPhase section */
212 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
213 | isa = PBXShellScriptBuildPhase;
214 | buildActionMask = 2147483647;
215 | files = (
216 | );
217 | inputPaths = (
218 | );
219 | name = "Thin Binary";
220 | outputPaths = (
221 | );
222 | runOnlyForDeploymentPostprocessing = 0;
223 | shellPath = /bin/sh;
224 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
225 | };
226 | 9740EEB61CF901F6004384FC /* Run Script */ = {
227 | isa = PBXShellScriptBuildPhase;
228 | buildActionMask = 2147483647;
229 | files = (
230 | );
231 | inputPaths = (
232 | );
233 | name = "Run Script";
234 | outputPaths = (
235 | );
236 | runOnlyForDeploymentPostprocessing = 0;
237 | shellPath = /bin/sh;
238 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
239 | };
240 | F648A867F04CC1FB7002D25D /* [CP] Check Pods Manifest.lock */ = {
241 | isa = PBXShellScriptBuildPhase;
242 | buildActionMask = 2147483647;
243 | files = (
244 | );
245 | inputFileListPaths = (
246 | );
247 | inputPaths = (
248 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
249 | "${PODS_ROOT}/Manifest.lock",
250 | );
251 | name = "[CP] Check Pods Manifest.lock";
252 | outputFileListPaths = (
253 | );
254 | outputPaths = (
255 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
256 | );
257 | runOnlyForDeploymentPostprocessing = 0;
258 | shellPath = /bin/sh;
259 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
260 | showEnvVarsInLog = 0;
261 | };
262 | /* End PBXShellScriptBuildPhase section */
263 |
264 | /* Begin PBXSourcesBuildPhase section */
265 | 97C146EA1CF9000F007C117D /* Sources */ = {
266 | isa = PBXSourcesBuildPhase;
267 | buildActionMask = 2147483647;
268 | files = (
269 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
270 | 97C146F31CF9000F007C117D /* main.m in Sources */,
271 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
272 | );
273 | runOnlyForDeploymentPostprocessing = 0;
274 | };
275 | /* End PBXSourcesBuildPhase section */
276 |
277 | /* Begin PBXVariantGroup section */
278 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
279 | isa = PBXVariantGroup;
280 | children = (
281 | 97C146FB1CF9000F007C117D /* Base */,
282 | );
283 | name = Main.storyboard;
284 | sourceTree = "";
285 | };
286 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
287 | isa = PBXVariantGroup;
288 | children = (
289 | 97C147001CF9000F007C117D /* Base */,
290 | );
291 | name = LaunchScreen.storyboard;
292 | sourceTree = "";
293 | };
294 | /* End PBXVariantGroup section */
295 |
296 | /* Begin XCBuildConfiguration section */
297 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
298 | isa = XCBuildConfiguration;
299 | buildSettings = {
300 | ALWAYS_SEARCH_USER_PATHS = NO;
301 | CLANG_ANALYZER_NONNULL = YES;
302 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
303 | CLANG_CXX_LIBRARY = "libc++";
304 | CLANG_ENABLE_MODULES = YES;
305 | CLANG_ENABLE_OBJC_ARC = YES;
306 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
307 | CLANG_WARN_BOOL_CONVERSION = YES;
308 | CLANG_WARN_COMMA = YES;
309 | CLANG_WARN_CONSTANT_CONVERSION = YES;
310 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
311 | CLANG_WARN_EMPTY_BODY = YES;
312 | CLANG_WARN_ENUM_CONVERSION = YES;
313 | CLANG_WARN_INFINITE_RECURSION = YES;
314 | CLANG_WARN_INT_CONVERSION = YES;
315 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
316 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
317 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
318 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
319 | CLANG_WARN_STRICT_PROTOTYPES = YES;
320 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
321 | CLANG_WARN_UNREACHABLE_CODE = YES;
322 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
323 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
324 | COPY_PHASE_STRIP = NO;
325 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
326 | ENABLE_NS_ASSERTIONS = NO;
327 | ENABLE_STRICT_OBJC_MSGSEND = YES;
328 | GCC_C_LANGUAGE_STANDARD = gnu99;
329 | GCC_NO_COMMON_BLOCKS = YES;
330 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
331 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
332 | GCC_WARN_UNDECLARED_SELECTOR = YES;
333 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
334 | GCC_WARN_UNUSED_FUNCTION = YES;
335 | GCC_WARN_UNUSED_VARIABLE = YES;
336 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
337 | MTL_ENABLE_DEBUG_INFO = NO;
338 | SDKROOT = iphoneos;
339 | TARGETED_DEVICE_FAMILY = "1,2";
340 | VALIDATE_PRODUCT = YES;
341 | };
342 | name = Profile;
343 | };
344 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
345 | isa = XCBuildConfiguration;
346 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
347 | buildSettings = {
348 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
349 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
350 | DEVELOPMENT_TEAM = 544P5CH38C;
351 | ENABLE_BITCODE = NO;
352 | FRAMEWORK_SEARCH_PATHS = (
353 | "$(inherited)",
354 | "$(PROJECT_DIR)/Flutter",
355 | );
356 | INFOPLIST_FILE = Runner/Info.plist;
357 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
358 | LIBRARY_SEARCH_PATHS = (
359 | "$(inherited)",
360 | "$(PROJECT_DIR)/Flutter",
361 | );
362 | PRODUCT_BUNDLE_IDENTIFIER = com.opensource.svgaplayerFlutterExample;
363 | PRODUCT_NAME = "$(TARGET_NAME)";
364 | VERSIONING_SYSTEM = "apple-generic";
365 | };
366 | name = Profile;
367 | };
368 | 97C147031CF9000F007C117D /* Debug */ = {
369 | isa = XCBuildConfiguration;
370 | buildSettings = {
371 | ALWAYS_SEARCH_USER_PATHS = NO;
372 | CLANG_ANALYZER_NONNULL = YES;
373 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
374 | CLANG_CXX_LIBRARY = "libc++";
375 | CLANG_ENABLE_MODULES = YES;
376 | CLANG_ENABLE_OBJC_ARC = YES;
377 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
378 | CLANG_WARN_BOOL_CONVERSION = YES;
379 | CLANG_WARN_COMMA = YES;
380 | CLANG_WARN_CONSTANT_CONVERSION = YES;
381 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
382 | CLANG_WARN_EMPTY_BODY = YES;
383 | CLANG_WARN_ENUM_CONVERSION = YES;
384 | CLANG_WARN_INFINITE_RECURSION = YES;
385 | CLANG_WARN_INT_CONVERSION = YES;
386 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
387 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
388 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
389 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
390 | CLANG_WARN_STRICT_PROTOTYPES = YES;
391 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
392 | CLANG_WARN_UNREACHABLE_CODE = YES;
393 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
394 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
395 | COPY_PHASE_STRIP = NO;
396 | DEBUG_INFORMATION_FORMAT = dwarf;
397 | ENABLE_STRICT_OBJC_MSGSEND = YES;
398 | ENABLE_TESTABILITY = YES;
399 | GCC_C_LANGUAGE_STANDARD = gnu99;
400 | GCC_DYNAMIC_NO_PIC = NO;
401 | GCC_NO_COMMON_BLOCKS = YES;
402 | GCC_OPTIMIZATION_LEVEL = 0;
403 | GCC_PREPROCESSOR_DEFINITIONS = (
404 | "DEBUG=1",
405 | "$(inherited)",
406 | );
407 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
408 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
409 | GCC_WARN_UNDECLARED_SELECTOR = YES;
410 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
411 | GCC_WARN_UNUSED_FUNCTION = YES;
412 | GCC_WARN_UNUSED_VARIABLE = YES;
413 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
414 | MTL_ENABLE_DEBUG_INFO = YES;
415 | ONLY_ACTIVE_ARCH = YES;
416 | SDKROOT = iphoneos;
417 | TARGETED_DEVICE_FAMILY = "1,2";
418 | };
419 | name = Debug;
420 | };
421 | 97C147041CF9000F007C117D /* Release */ = {
422 | isa = XCBuildConfiguration;
423 | buildSettings = {
424 | ALWAYS_SEARCH_USER_PATHS = NO;
425 | CLANG_ANALYZER_NONNULL = YES;
426 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
427 | CLANG_CXX_LIBRARY = "libc++";
428 | CLANG_ENABLE_MODULES = YES;
429 | CLANG_ENABLE_OBJC_ARC = YES;
430 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
431 | CLANG_WARN_BOOL_CONVERSION = YES;
432 | CLANG_WARN_COMMA = YES;
433 | CLANG_WARN_CONSTANT_CONVERSION = YES;
434 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
435 | CLANG_WARN_EMPTY_BODY = YES;
436 | CLANG_WARN_ENUM_CONVERSION = YES;
437 | CLANG_WARN_INFINITE_RECURSION = YES;
438 | CLANG_WARN_INT_CONVERSION = YES;
439 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
440 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
441 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
442 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
443 | CLANG_WARN_STRICT_PROTOTYPES = YES;
444 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
445 | CLANG_WARN_UNREACHABLE_CODE = YES;
446 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
447 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
448 | COPY_PHASE_STRIP = NO;
449 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
450 | ENABLE_NS_ASSERTIONS = NO;
451 | ENABLE_STRICT_OBJC_MSGSEND = YES;
452 | GCC_C_LANGUAGE_STANDARD = gnu99;
453 | GCC_NO_COMMON_BLOCKS = YES;
454 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
455 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
456 | GCC_WARN_UNDECLARED_SELECTOR = YES;
457 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
458 | GCC_WARN_UNUSED_FUNCTION = YES;
459 | GCC_WARN_UNUSED_VARIABLE = YES;
460 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
461 | MTL_ENABLE_DEBUG_INFO = NO;
462 | SDKROOT = iphoneos;
463 | TARGETED_DEVICE_FAMILY = "1,2";
464 | VALIDATE_PRODUCT = YES;
465 | };
466 | name = Release;
467 | };
468 | 97C147061CF9000F007C117D /* Debug */ = {
469 | isa = XCBuildConfiguration;
470 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
471 | buildSettings = {
472 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
473 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
474 | DEVELOPMENT_TEAM = 544P5CH38C;
475 | ENABLE_BITCODE = NO;
476 | FRAMEWORK_SEARCH_PATHS = (
477 | "$(inherited)",
478 | "$(PROJECT_DIR)/Flutter",
479 | );
480 | INFOPLIST_FILE = Runner/Info.plist;
481 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
482 | LIBRARY_SEARCH_PATHS = (
483 | "$(inherited)",
484 | "$(PROJECT_DIR)/Flutter",
485 | );
486 | PRODUCT_BUNDLE_IDENTIFIER = com.opensource.svgaplayerFlutterExample;
487 | PRODUCT_NAME = "$(TARGET_NAME)";
488 | VERSIONING_SYSTEM = "apple-generic";
489 | };
490 | name = Debug;
491 | };
492 | 97C147071CF9000F007C117D /* Release */ = {
493 | isa = XCBuildConfiguration;
494 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
495 | buildSettings = {
496 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
497 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
498 | DEVELOPMENT_TEAM = 544P5CH38C;
499 | ENABLE_BITCODE = NO;
500 | FRAMEWORK_SEARCH_PATHS = (
501 | "$(inherited)",
502 | "$(PROJECT_DIR)/Flutter",
503 | );
504 | INFOPLIST_FILE = Runner/Info.plist;
505 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
506 | LIBRARY_SEARCH_PATHS = (
507 | "$(inherited)",
508 | "$(PROJECT_DIR)/Flutter",
509 | );
510 | PRODUCT_BUNDLE_IDENTIFIER = com.opensource.svgaplayerFlutterExample;
511 | PRODUCT_NAME = "$(TARGET_NAME)";
512 | VERSIONING_SYSTEM = "apple-generic";
513 | };
514 | name = Release;
515 | };
516 | /* End XCBuildConfiguration section */
517 |
518 | /* Begin XCConfigurationList section */
519 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
520 | isa = XCConfigurationList;
521 | buildConfigurations = (
522 | 97C147031CF9000F007C117D /* Debug */,
523 | 97C147041CF9000F007C117D /* Release */,
524 | 249021D3217E4FDB00AE95B9 /* Profile */,
525 | );
526 | defaultConfigurationIsVisible = 0;
527 | defaultConfigurationName = Release;
528 | };
529 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
530 | isa = XCConfigurationList;
531 | buildConfigurations = (
532 | 97C147061CF9000F007C117D /* Debug */,
533 | 97C147071CF9000F007C117D /* Release */,
534 | 249021D4217E4FDB00AE95B9 /* Profile */,
535 | );
536 | defaultConfigurationIsVisible = 0;
537 | defaultConfigurationName = Release;
538 | };
539 | /* End XCConfigurationList section */
540 | };
541 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
542 | }
543 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svga/SVGAPlayer-Flutter/de7de7036797b47c0df431fef67e4d8051b162af/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | svgaplayer_flutter_example
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/example/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math' as math;
2 | import 'package:flutter/foundation.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:svgaplayer_flutter/svgaplayer_flutter.dart';
5 |
6 | void main() => runApp(ExampleApp());
7 |
8 | class ExampleApp extends StatelessWidget {
9 | @override
10 | Widget build(BuildContext context) {
11 | return MaterialApp(theme: ThemeData.dark(), home: HomeScreen());
12 | }
13 | }
14 |
15 | class HomeScreen extends StatelessWidget {
16 | final samples = const [
17 | "assets/angel.svga",
18 | "assets/pin_jump.svga",
19 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/EmptyState.svga",
20 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/HamburgerArrow.svga",
21 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/PinJump.svga",
22 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/TwitterHeart.svga",
23 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/Walkthrough.svga",
24 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/kingset.svga",
25 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/halloween.svga",
26 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/heartbeat.svga",
27 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/matteBitmap.svga",
28 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/matteBitmap_1.x.svga",
29 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/matteRect.svga",
30 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/mutiMatte.svga",
31 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/posche.svga",
32 | "https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/rose.svga",
33 | ].map((e) => [e.split('/').last, e]).toList(growable: false);
34 |
35 | // callback for register dynamicItem
36 | final dynamicSamples = {
37 | "kingset.svga": (entity) => entity.dynamicItem
38 | ..setText(
39 | TextPainter(
40 | text: TextSpan(
41 | text: "Hello, World!",
42 | style: TextStyle(
43 | fontSize: 28,
44 | color: Colors.white,
45 | fontWeight: FontWeight.bold,
46 | ))),
47 | "banner")
48 | // ..setImageWithUrl(
49 | // "https://github.com/PonyCui/resources/blob/master/svga_replace_avatar.png?raw=true",
50 | // "99")
51 | // ..setDynamicDrawer((canvas, frameIndex) {
52 | // canvas.drawRect(Rect.fromLTWH(0, 0, 88, 88),
53 | // Paint()..color = Colors.red); // draw by yourself.
54 | // }, "banner"),
55 | };
56 |
57 | @override
58 | Widget build(BuildContext context) {
59 | return Scaffold(
60 | appBar: AppBar(title: Text('SVGA Flutter Samples')),
61 | body: ListView.separated(
62 | itemCount: samples.length,
63 | separatorBuilder: (_, __) => Divider(),
64 | itemBuilder: (context, index) {
65 | return ListTile(
66 | title: Text(samples[index].first),
67 | subtitle: Text(samples[index].last),
68 | onTap: () => _goToSample(context, samples[index]));
69 | }),
70 | );
71 | }
72 |
73 | void _goToSample(context, List sample) {
74 | Navigator.of(context).push(MaterialPageRoute(builder: (context) {
75 | return SVGASampleScreen(
76 | name: sample.first,
77 | image: sample.last,
78 | dynamicCallback: dynamicSamples[sample.first]);
79 | }));
80 | }
81 | }
82 |
83 | class SVGASampleScreen extends StatefulWidget {
84 | final String? name;
85 | final String image;
86 | final void Function(MovieEntity entity)? dynamicCallback;
87 | const SVGASampleScreen(
88 | {Key? key, required this.image, this.name, this.dynamicCallback})
89 | : super(key: key);
90 |
91 | @override
92 | _SVGASampleScreenState createState() => _SVGASampleScreenState();
93 | }
94 |
95 | class _SVGASampleScreenState extends State
96 | with SingleTickerProviderStateMixin {
97 | SVGAAnimationController? animationController;
98 | bool isLoading = true;
99 | Color backgroundColor = Colors.transparent;
100 | bool allowOverflow = true;
101 | // Canvaskit need FilterQuality.high
102 | FilterQuality filterQuality = kIsWeb ? FilterQuality.high : FilterQuality.low;
103 | BoxFit fit = BoxFit.contain;
104 | late double containerWidth;
105 | late double containerHeight;
106 | bool hideOptions = false;
107 | @override
108 | void initState() {
109 | super.initState();
110 | this.animationController = SVGAAnimationController(vsync: this);
111 | this._loadAnimation();
112 | }
113 |
114 | @override
115 | void didChangeDependencies() {
116 | super.didChangeDependencies();
117 | containerWidth = math.min(350, MediaQuery.of(context).size.width);
118 | containerHeight = math.min(350, MediaQuery.of(context).size.height);
119 | }
120 |
121 | @override
122 | void dispose() {
123 | this.animationController?.dispose();
124 | this.animationController = null;
125 | super.dispose();
126 | }
127 |
128 | void _loadAnimation() async {
129 | // FIXME: may throw error on loading
130 | final videoItem = await _loadVideoItem(widget.image);
131 | if (widget.dynamicCallback != null) {
132 | widget.dynamicCallback!(videoItem);
133 | }
134 | if (mounted)
135 | setState(() {
136 | this.isLoading = false;
137 | this.animationController?.videoItem = videoItem;
138 | _playAnimation();
139 | });
140 | }
141 |
142 | void _playAnimation() {
143 | if (animationController?.isCompleted == true) {
144 | animationController?.reset();
145 | }
146 | animationController?.repeat(); // or animationController.forward();
147 | }
148 |
149 | @override
150 | Widget build(BuildContext context) {
151 | return Scaffold(
152 | appBar: AppBar(title: Text(widget.name ?? "")),
153 | body: Stack(
154 | children: [
155 | Container(
156 | padding: const EdgeInsets.all(8.0),
157 | child: Text("Url: ${widget.image}",
158 | style: Theme.of(context).textTheme.subtitle2)),
159 | if (isLoading) LinearProgressIndicator(),
160 | Center(
161 | child: ColoredBox(
162 | color: backgroundColor,
163 | child: SVGAImage(
164 | this.animationController!,
165 | fit: fit,
166 | clearsAfterStop: false,
167 | allowDrawingOverflow: allowOverflow,
168 | filterQuality: filterQuality,
169 | preferredSize: Size(containerWidth, containerHeight),
170 | ),
171 | ),
172 | ),
173 | Positioned(bottom: 10, child: _buildOptions(context)),
174 | ],
175 | ),
176 | floatingActionButton: isLoading || animationController!.videoItem == null
177 | ? null
178 | : FloatingActionButton.extended(
179 | label: Text(animationController!.isAnimating ? "Pause" : "Play"),
180 | icon: Icon(animationController!.isAnimating
181 | ? Icons.pause
182 | : Icons.play_arrow),
183 | onPressed: () {
184 | if (animationController?.isAnimating == true) {
185 | animationController?.stop();
186 | } else {
187 | _playAnimation();
188 | }
189 | setState(() {});
190 | }),
191 | );
192 | }
193 |
194 | Widget _buildOptions(BuildContext context) {
195 | return Container(
196 | width: 240,
197 | color: Colors.black12,
198 | padding: EdgeInsets.all(8.0),
199 | child: SliderTheme(
200 | data: SliderTheme.of(context).copyWith(
201 | showValueIndicator: ShowValueIndicator.always,
202 | trackHeight: 2,
203 | overlayShape: const RoundSliderOverlayShape(overlayRadius: 10),
204 | thumbShape: const RoundSliderThumbShape(
205 | enabledThumbRadius: 6, pressedElevation: 4),
206 | ),
207 | child: Column(
208 | crossAxisAlignment: CrossAxisAlignment.start,
209 | children: [
210 | TextButton.icon(
211 | onPressed: () {
212 | setState(() {
213 | hideOptions = !hideOptions;
214 | });
215 | },
216 | icon: hideOptions
217 | ? Icon(Icons.arrow_drop_up)
218 | : Icon(Icons.arrow_drop_down),
219 | label: Text(hideOptions ? 'Show options' : 'Hide options')),
220 | AnimatedBuilder(
221 | animation: animationController!,
222 | builder: (context, child) {
223 | return Text(
224 | 'Current frame: ${animationController!.currentFrame + 1}/${animationController!.frames}');
225 | }),
226 | if (!hideOptions) ...[
227 | AnimatedBuilder(
228 | animation: animationController!,
229 | builder: (context, child) {
230 | return Slider(
231 | min: 0,
232 | max: animationController!.frames.toDouble(),
233 | value: animationController!.currentFrame.toDouble(),
234 | label: '${animationController!.currentFrame}',
235 | onChanged: (v) {
236 | if (animationController?.isAnimating == true) {
237 | animationController?.stop();
238 | }
239 | animationController?.value =
240 | v / animationController!.frames;
241 | },
242 | );
243 | }),
244 | Row(
245 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
246 | children: [
247 | Text('Image filter quality'),
248 | DropdownButton(
249 | value: filterQuality,
250 | onChanged: (FilterQuality? newValue) {
251 | setState(() {
252 | filterQuality = newValue!;
253 | });
254 | },
255 | items: FilterQuality.values.map((FilterQuality value) {
256 | return DropdownMenuItem(
257 | value: value,
258 | child: Text(value.toString().split('.').last),
259 | );
260 | }).toList(),
261 | )
262 | ],
263 | ),
264 | const SizedBox(height: 8),
265 | Row(
266 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
267 | children: [
268 | Text('Allow drawing overflow'),
269 | const SizedBox(width: 8),
270 | Switch(
271 | value: allowOverflow,
272 | onChanged: (v) {
273 | setState(() {
274 | allowOverflow = v;
275 | });
276 | },
277 | )
278 | ],
279 | ),
280 | Text('Container options:'),
281 | Row(
282 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
283 | children: [
284 | Text(' width:'),
285 | Slider(
286 | min: 100,
287 | max: MediaQuery.of(context).size.width.roundToDouble(),
288 | value: containerWidth,
289 | label: '$containerWidth',
290 | onChanged: (v) {
291 | setState(() {
292 | containerWidth = v.truncateToDouble();
293 | });
294 | },
295 | ),
296 | ],
297 | ),
298 | Row(
299 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
300 | children: [
301 | Text(' height:'),
302 | Slider(
303 | min: 100,
304 | max: MediaQuery.of(context).size.height.roundToDouble(),
305 | label: '$containerHeight',
306 | value: containerHeight,
307 | onChanged: (v) {
308 | setState(() {
309 | containerHeight = v.truncateToDouble();
310 | });
311 | },
312 | ),
313 | ],
314 | ),
315 | Row(
316 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
317 | children: [
318 | Text(' box fit: '),
319 | const SizedBox(width: 8),
320 | DropdownButton(
321 | value: fit,
322 | onChanged: (BoxFit? newValue) {
323 | setState(() {
324 | fit = newValue!;
325 | });
326 | },
327 | items: BoxFit.values.map((BoxFit value) {
328 | return DropdownMenuItem(
329 | value: value,
330 | child: Text(value.toString().split('.').last),
331 | );
332 | }).toList(),
333 | )
334 | ],
335 | ),
336 | Row(
337 | mainAxisAlignment: MainAxisAlignment.spaceAround,
338 | children: const [
339 | Colors.transparent,
340 | Colors.red,
341 | Colors.green,
342 | Colors.blue,
343 | Colors.yellow,
344 | Colors.black,
345 | ]
346 | .map(
347 | (e) => GestureDetector(
348 | onTap: () {
349 | setState(() {
350 | backgroundColor = e;
351 | });
352 | },
353 | child: Container(
354 | width: 20,
355 | height: 20,
356 | decoration: ShapeDecoration(
357 | color: e,
358 | shape: CircleBorder(
359 | side: backgroundColor == e
360 | ? const BorderSide(
361 | color: Colors.white,
362 | width: 3,
363 | )
364 | : const BorderSide(color: Colors.grey),
365 | ),
366 | ),
367 | ),
368 | ),
369 | )
370 | .toList(),
371 | ),
372 | ],
373 | ],
374 | ),
375 | ),
376 | );
377 | }
378 | }
379 |
380 | Future _loadVideoItem(String image) {
381 | Future Function(String) decoder;
382 | if (image.startsWith(RegExp(r'https?://'))) {
383 | decoder = SVGAParser.shared.decodeFromURL;
384 | } else {
385 | decoder = SVGAParser.shared.decodeFromAssets;
386 | }
387 | return decoder(image);
388 | }
389 |
--------------------------------------------------------------------------------
/example/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | archive:
5 | dependency: transitive
6 | description:
7 | name: archive
8 | url: "https://pub.flutter-io.cn"
9 | source: hosted
10 | version: "3.1.2"
11 | async:
12 | dependency: transitive
13 | description:
14 | name: async
15 | url: "https://pub.flutter-io.cn"
16 | source: hosted
17 | version: "2.9.0"
18 | boolean_selector:
19 | dependency: transitive
20 | description:
21 | name: boolean_selector
22 | url: "https://pub.flutter-io.cn"
23 | source: hosted
24 | version: "2.1.0"
25 | characters:
26 | dependency: transitive
27 | description:
28 | name: characters
29 | url: "https://pub.flutter-io.cn"
30 | source: hosted
31 | version: "1.2.1"
32 | charcode:
33 | dependency: transitive
34 | description:
35 | name: charcode
36 | url: "https://pub.flutter-io.cn"
37 | source: hosted
38 | version: "1.3.1"
39 | clock:
40 | dependency: transitive
41 | description:
42 | name: clock
43 | url: "https://pub.flutter-io.cn"
44 | source: hosted
45 | version: "1.1.1"
46 | collection:
47 | dependency: transitive
48 | description:
49 | name: collection
50 | url: "https://pub.flutter-io.cn"
51 | source: hosted
52 | version: "1.16.0"
53 | crypto:
54 | dependency: transitive
55 | description:
56 | name: crypto
57 | url: "https://pub.flutter-io.cn"
58 | source: hosted
59 | version: "3.0.1"
60 | cupertino_icons:
61 | dependency: "direct main"
62 | description:
63 | name: cupertino_icons
64 | url: "https://pub.flutter-io.cn"
65 | source: hosted
66 | version: "0.1.2"
67 | fake_async:
68 | dependency: transitive
69 | description:
70 | name: fake_async
71 | url: "https://pub.flutter-io.cn"
72 | source: hosted
73 | version: "1.3.1"
74 | fixnum:
75 | dependency: transitive
76 | description:
77 | name: fixnum
78 | url: "https://pub.flutter-io.cn"
79 | source: hosted
80 | version: "1.0.0"
81 | flutter:
82 | dependency: "direct main"
83 | description: flutter
84 | source: sdk
85 | version: "0.0.0"
86 | flutter_test:
87 | dependency: "direct dev"
88 | description: flutter
89 | source: sdk
90 | version: "0.0.0"
91 | http:
92 | dependency: transitive
93 | description:
94 | name: http
95 | url: "https://pub.flutter-io.cn"
96 | source: hosted
97 | version: "0.13.3"
98 | http_parser:
99 | dependency: transitive
100 | description:
101 | name: http_parser
102 | url: "https://pub.flutter-io.cn"
103 | source: hosted
104 | version: "4.0.0"
105 | matcher:
106 | dependency: transitive
107 | description:
108 | name: matcher
109 | url: "https://pub.flutter-io.cn"
110 | source: hosted
111 | version: "0.12.12"
112 | material_color_utilities:
113 | dependency: transitive
114 | description:
115 | name: material_color_utilities
116 | url: "https://pub.flutter-io.cn"
117 | source: hosted
118 | version: "0.1.5"
119 | meta:
120 | dependency: transitive
121 | description:
122 | name: meta
123 | url: "https://pub.flutter-io.cn"
124 | source: hosted
125 | version: "1.8.0"
126 | path:
127 | dependency: transitive
128 | description:
129 | name: path
130 | url: "https://pub.flutter-io.cn"
131 | source: hosted
132 | version: "1.8.2"
133 | path_drawing:
134 | dependency: transitive
135 | description:
136 | name: path_drawing
137 | url: "https://pub.flutter-io.cn"
138 | source: hosted
139 | version: "1.0.1"
140 | path_parsing:
141 | dependency: transitive
142 | description:
143 | name: path_parsing
144 | url: "https://pub.flutter-io.cn"
145 | source: hosted
146 | version: "1.0.1"
147 | pedantic:
148 | dependency: transitive
149 | description:
150 | name: pedantic
151 | url: "https://pub.flutter-io.cn"
152 | source: hosted
153 | version: "1.11.0"
154 | protobuf:
155 | dependency: transitive
156 | description:
157 | name: protobuf
158 | url: "https://pub.flutter-io.cn"
159 | source: hosted
160 | version: "2.0.0"
161 | sky_engine:
162 | dependency: transitive
163 | description: flutter
164 | source: sdk
165 | version: "0.0.99"
166 | source_span:
167 | dependency: transitive
168 | description:
169 | name: source_span
170 | url: "https://pub.flutter-io.cn"
171 | source: hosted
172 | version: "1.9.0"
173 | stack_trace:
174 | dependency: transitive
175 | description:
176 | name: stack_trace
177 | url: "https://pub.flutter-io.cn"
178 | source: hosted
179 | version: "1.10.0"
180 | stream_channel:
181 | dependency: transitive
182 | description:
183 | name: stream_channel
184 | url: "https://pub.flutter-io.cn"
185 | source: hosted
186 | version: "2.1.0"
187 | string_scanner:
188 | dependency: transitive
189 | description:
190 | name: string_scanner
191 | url: "https://pub.flutter-io.cn"
192 | source: hosted
193 | version: "1.1.1"
194 | svgaplayer_flutter:
195 | dependency: "direct dev"
196 | description:
197 | path: ".."
198 | relative: true
199 | source: path
200 | version: "2.1.2"
201 | term_glyph:
202 | dependency: transitive
203 | description:
204 | name: term_glyph
205 | url: "https://pub.flutter-io.cn"
206 | source: hosted
207 | version: "1.2.1"
208 | test_api:
209 | dependency: transitive
210 | description:
211 | name: test_api
212 | url: "https://pub.flutter-io.cn"
213 | source: hosted
214 | version: "0.4.12"
215 | typed_data:
216 | dependency: transitive
217 | description:
218 | name: typed_data
219 | url: "https://pub.flutter-io.cn"
220 | source: hosted
221 | version: "1.3.0"
222 | vector_math:
223 | dependency: transitive
224 | description:
225 | name: vector_math
226 | url: "https://pub.flutter-io.cn"
227 | source: hosted
228 | version: "2.1.2"
229 | sdks:
230 | dart: ">=2.17.0-0 <3.0.0"
231 | flutter: ">=1.24.0-7.0"
232 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: svgaplayer_flutter_example
2 | description: Demonstrates how to use the svgaplayer_flutter plugin.
3 | publish_to: 'none'
4 |
5 | environment:
6 | sdk: ">=2.12.0 <3.0.0"
7 |
8 | dependencies:
9 | flutter:
10 | sdk: flutter
11 |
12 | # The following adds the Cupertino Icons font to your application.
13 | # Use with the CupertinoIcons class for iOS style icons.
14 | cupertino_icons: ^0.1.2
15 |
16 | dev_dependencies:
17 | flutter_test:
18 | sdk: flutter
19 |
20 | svgaplayer_flutter:
21 | path: ../
22 |
23 | # For information on the generic Dart part of this file, see the
24 | # following page: https://www.dartlang.org/tools/pub/pubspec
25 |
26 | # The following section is specific to Flutter.
27 | flutter:
28 |
29 | # The following line ensures that the Material Icons font is
30 | # included with your application, so that you can use the icons in
31 | # the material Icons class.
32 | uses-material-design: true
33 |
34 | # To add assets to your application, add an assets section, like this:
35 | assets:
36 | - assets/pin_jump.svga
37 | - assets/angel.svga
38 |
39 | # An image asset can refer to one or more resolution-specific "variants", see
40 | # https://flutter.io/assets-and-images/#resolution-aware.
41 |
42 | # For details regarding adding assets from package dependencies, see
43 | # https://flutter.io/assets-and-images/#from-packages
44 |
45 | # To add custom fonts to your application, add a fonts section here,
46 | # in this "flutter" section. Each entry in this list should have a
47 | # "family" key with the font family name, and a "fonts" key with a
48 | # list giving the asset and other descriptors for the font. For
49 | # example:
50 | # fonts:
51 | # - family: Schyler
52 | # fonts:
53 | # - asset: fonts/Schyler-Regular.ttf
54 | # - asset: fonts/Schyler-Italic.ttf
55 | # style: italic
56 | # - family: Trajan Pro
57 | # fonts:
58 | # - asset: fonts/TrajanPro.ttf
59 | # - asset: fonts/TrajanPro_Bold.ttf
60 | # weight: 700
61 | #
62 | # For details regarding fonts from package dependencies,
63 | # see https://flutter.io/custom-fonts/#from-packages
64 |
--------------------------------------------------------------------------------
/example/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | void main() {}
9 |
--------------------------------------------------------------------------------
/example/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | example
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/dynamic_entity.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui' as ui show Image;
2 | import 'package:http/http.dart';
3 | import 'package:flutter/painting.dart';
4 |
5 | typedef SVGACustomDrawer = Function(Canvas canvas, int frameIndex);
6 |
7 | class SVGADynamicEntity {
8 | final Map dynamicHidden = {};
9 | final Map dynamicImages = {};
10 | final Map dynamicText = {};
11 | final Map dynamicDrawer = {};
12 |
13 | void setHidden(bool value, String forKey) {
14 | this.dynamicHidden[forKey] = value;
15 | }
16 |
17 | void setImage(ui.Image image, String forKey) {
18 | this.dynamicImages[forKey] = image;
19 | }
20 |
21 | Future setImageWithUrl(String url, String forKey) async {
22 | this.dynamicImages[forKey] =
23 | await decodeImageFromList((await get(Uri.parse(url))).bodyBytes);
24 | }
25 |
26 | void setText(TextPainter textPainter, String forKey) {
27 | if (textPainter.textDirection == null) {
28 | textPainter.textDirection = TextDirection.ltr;
29 | textPainter.layout();
30 | }
31 | this.dynamicText[forKey] = textPainter;
32 | }
33 |
34 | void setDynamicDrawer(SVGACustomDrawer drawer, String forKey) {
35 | this.dynamicDrawer[forKey] = drawer;
36 | }
37 |
38 | void reset() {
39 | this.dynamicHidden.clear();
40 | this.dynamicImages.clear();
41 | this.dynamicText.clear();
42 | this.dynamicDrawer.clear();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/painter.dart:
--------------------------------------------------------------------------------
1 | part of svgaplayer_flutter_player;
2 |
3 | class _SVGAPainter extends CustomPainter {
4 | final BoxFit fit;
5 | final SVGAAnimationController controller;
6 | int get currentFrame => controller.currentFrame;
7 | MovieEntity get videoItem => controller.videoItem!;
8 | final FilterQuality filterQuality;
9 |
10 | /// Guaranteed to draw within the canvas bounds
11 | final bool clipRect;
12 | _SVGAPainter(
13 | this.controller, {
14 | this.fit = BoxFit.contain,
15 | this.filterQuality = FilterQuality.low,
16 | this.clipRect = true,
17 | }) : assert(
18 | controller.videoItem != null, 'Invalid SVGAAnimationController!'),
19 | super(repaint: controller);
20 |
21 | @override
22 | void paint(Canvas canvas, Size size) {
23 | if (controller._canvasNeedsClear) {
24 | // mark cleared
25 | controller._canvasNeedsClear = false;
26 | return;
27 | }
28 | if (size.isEmpty || controller.videoItem == null) return;
29 | final params = videoItem.params;
30 | final Size viewBoxSize = Size(params.viewBoxWidth, params.viewBoxHeight);
31 | if (viewBoxSize.isEmpty) return;
32 | canvas.save();
33 | try {
34 | final canvasRect = Offset.zero & size;
35 | if (clipRect) canvas.clipRect(canvasRect);
36 | scaleCanvasToViewBox(canvas, canvasRect, Offset.zero & viewBoxSize);
37 | drawSprites(canvas, size);
38 | } finally {
39 | canvas.restore();
40 | }
41 | }
42 |
43 | void scaleCanvasToViewBox(Canvas canvas, Rect canvasRect, Rect viewBoxRect) {
44 | final fittedSizes = applyBoxFit(fit, viewBoxRect.size, canvasRect.size);
45 |
46 | // scale viewbox size (source) to canvas size (destination)
47 | var sx = fittedSizes.destination.width / fittedSizes.source.width;
48 | var sy = fittedSizes.destination.height / fittedSizes.source.height;
49 | final Size scaledHalfViewBoxSize =
50 | Size(viewBoxRect.size.width * sx, viewBoxRect.size.height * sy) / 2.0;
51 | final Size halfCanvasSize = canvasRect.size / 2.0;
52 | // center align
53 | final Offset shift = Offset(
54 | halfCanvasSize.width - scaledHalfViewBoxSize.width,
55 | halfCanvasSize.height - scaledHalfViewBoxSize.height,
56 | );
57 | if (shift != Offset.zero) canvas.translate(shift.dx, shift.dy);
58 | if (sx != 1.0 && sy != 1.0) canvas.scale(sx, sy);
59 | }
60 |
61 | void drawSprites(Canvas canvas, Size size) {
62 | for (final sprite in videoItem.sprites) {
63 | final imageKey = sprite.imageKey;
64 | // var matteKey = sprite.matteKey;
65 | if (imageKey.isEmpty ||
66 | videoItem.dynamicItem.dynamicHidden[imageKey] == true) {
67 | continue;
68 | }
69 | final frameItem = sprite.frames[currentFrame];
70 | final needTransform = frameItem.hasTransform();
71 | final needClip = frameItem.hasClipPath();
72 | if (needTransform) {
73 | canvas.save();
74 | canvas.transform(Float64List.fromList([
75 | frameItem.transform.a,
76 | frameItem.transform.b,
77 | 0.0,
78 | 0.0,
79 | frameItem.transform.c,
80 | frameItem.transform.d,
81 | 0.0,
82 | 0.0,
83 | 0.0,
84 | 0.0,
85 | 1.0,
86 | 0.0,
87 | frameItem.transform.tx,
88 | frameItem.transform.ty,
89 | 0.0,
90 | 1.0
91 | ]));
92 | }
93 | if (needClip) {
94 | canvas.save();
95 | canvas.clipPath(buildDPath(frameItem.clipPath));
96 | }
97 | final frameRect =
98 | Rect.fromLTRB(0, 0, frameItem.layout.width, frameItem.layout.height);
99 | final frameAlpha =
100 | frameItem.hasAlpha() ? (frameItem.alpha * 255).toInt() : 255;
101 | drawBitmap(canvas, imageKey, frameRect, frameAlpha);
102 | drawShape(canvas, frameItem.shapes, frameAlpha);
103 | // draw dynamic
104 | final dynamicDrawer = videoItem.dynamicItem.dynamicDrawer[imageKey];
105 | if (dynamicDrawer != null) {
106 | dynamicDrawer(canvas, currentFrame);
107 | }
108 | if (needClip) {
109 | canvas.restore();
110 | }
111 | if (needTransform) {
112 | canvas.restore();
113 | }
114 | }
115 | }
116 |
117 | void drawBitmap(Canvas canvas, String imageKey, Rect frameRect, int alpha) {
118 | final bitmap = videoItem.dynamicItem.dynamicImages[imageKey] ??
119 | videoItem.bitmapCache[imageKey];
120 | if (bitmap == null) return;
121 |
122 | final bitmapPaint = Paint();
123 | bitmapPaint.filterQuality = filterQuality;
124 | //解决bitmap锯齿问题
125 | bitmapPaint.isAntiAlias = true;
126 | bitmapPaint.color = Color.fromARGB(alpha, 0, 0, 0);
127 |
128 | Rect srcRect =
129 | Rect.fromLTRB(0, 0, bitmap.width.toDouble(), bitmap.height.toDouble());
130 | Rect dstRect = frameRect;
131 | canvas.drawImageRect(bitmap, srcRect, dstRect, bitmapPaint);
132 | drawTextOnBitmap(canvas, imageKey, frameRect, alpha);
133 | }
134 |
135 | void drawShape(Canvas canvas, List shapes, int frameAlpha) {
136 | if (shapes.isEmpty) return;
137 | for (var shape in shapes) {
138 | final path = buildPath(shape);
139 | if (shape.hasTransform()) {
140 | canvas.save();
141 | canvas.transform(Float64List.fromList([
142 | shape.transform.a,
143 | shape.transform.b,
144 | 0.0,
145 | 0.0,
146 | shape.transform.c,
147 | shape.transform.d,
148 | 0.0,
149 | 0.0,
150 | 0.0,
151 | 0.0,
152 | 1.0,
153 | 0.0,
154 | shape.transform.tx,
155 | shape.transform.ty,
156 | 0.0,
157 | 1.0
158 | ]));
159 | }
160 |
161 | final fill = shape.styles.fill;
162 | if (fill.isInitialized()) {
163 | final paint = Paint();
164 | paint.isAntiAlias = true;
165 | paint.style = PaintingStyle.fill;
166 | paint.color = Color.fromARGB(
167 | (fill.a * frameAlpha).toInt(),
168 | (fill.r * 255).toInt(),
169 | (fill.g * 255).toInt(),
170 | (fill.b * 255).toInt(),
171 | );
172 | canvas.drawPath(path, paint);
173 | }
174 | final strokeWidth = shape.styles.strokeWidth;
175 | if (strokeWidth > 0) {
176 | final paint = Paint();
177 | paint.style = PaintingStyle.stroke;
178 | if (shape.styles.stroke.isInitialized()) {
179 | paint.color = Color.fromARGB(
180 | (shape.styles.stroke.a * frameAlpha).toInt(),
181 | (shape.styles.stroke.r * 255).toInt(),
182 | (shape.styles.stroke.g * 255).toInt(),
183 | (shape.styles.stroke.b * 255).toInt(),
184 | );
185 | }
186 | paint.strokeWidth = strokeWidth;
187 | final lineCap = shape.styles.lineCap;
188 | switch (lineCap) {
189 | case ShapeEntity_ShapeStyle_LineCap.LineCap_BUTT:
190 | paint.strokeCap = StrokeCap.butt;
191 | break;
192 | case ShapeEntity_ShapeStyle_LineCap.LineCap_ROUND:
193 | paint.strokeCap = StrokeCap.round;
194 | break;
195 | case ShapeEntity_ShapeStyle_LineCap.LineCap_SQUARE:
196 | paint.strokeCap = StrokeCap.square;
197 | break;
198 | default:
199 | }
200 | final lineJoin = shape.styles.lineJoin;
201 | switch (lineJoin) {
202 | case ShapeEntity_ShapeStyle_LineJoin.LineJoin_MITER:
203 | paint.strokeJoin = StrokeJoin.miter;
204 | break;
205 | case ShapeEntity_ShapeStyle_LineJoin.LineJoin_ROUND:
206 | paint.strokeJoin = StrokeJoin.round;
207 | break;
208 | case ShapeEntity_ShapeStyle_LineJoin.LineJoin_BEVEL:
209 | paint.strokeJoin = StrokeJoin.bevel;
210 | break;
211 | default:
212 | }
213 | paint.strokeMiterLimit = shape.styles.miterLimit;
214 | List lineDash = [
215 | shape.styles.lineDashI,
216 | shape.styles.lineDashII,
217 | shape.styles.lineDashIII
218 | ];
219 | if (lineDash[0] > 0 || lineDash[1] > 0) {
220 | canvas.drawPath(
221 | dashPath(
222 | path,
223 | dashArray: CircularIntervalList([
224 | lineDash[0] < 1.0 ? 1.0 : lineDash[0],
225 | lineDash[1] < 0.1 ? 0.1 : lineDash[1],
226 | ]),
227 | dashOffset: DashOffset.absolute(lineDash[2]),
228 | ),
229 | paint);
230 | } else {
231 | canvas.drawPath(path, paint);
232 | }
233 | }
234 | if (shape.hasTransform()) {
235 | canvas.restore();
236 | }
237 | }
238 | }
239 |
240 | static const _validMethods = 'MLHVCSQRZmlhvcsqrz';
241 |
242 | Path buildPath(ShapeEntity shape) {
243 | final path = Path();
244 | if (shape.type == ShapeEntity_ShapeType.SHAPE) {
245 | final args = shape.shape;
246 | final argD = args.d;
247 | return buildDPath(argD, path: path);
248 | } else if (shape.type == ShapeEntity_ShapeType.ELLIPSE) {
249 | final args = shape.ellipse;
250 | final xv = args.x;
251 | final yv = args.y;
252 | final rxv = args.radiusX;
253 | final ryv = args.radiusY;
254 | final rect = Rect.fromLTWH(xv - rxv, yv - ryv, rxv * 2, ryv * 2);
255 | if (!rect.isEmpty) path.addOval(rect);
256 | } else if (shape.type == ShapeEntity_ShapeType.RECT) {
257 | final args = shape.rect;
258 | final xv = args.x;
259 | final yv = args.y;
260 | final wv = args.width;
261 | final hv = args.height;
262 | final crv = args.cornerRadius;
263 | final rrect = RRect.fromRectAndRadius(
264 | Rect.fromLTWH(xv, yv, wv, hv), Radius.circular(crv));
265 | if (!rrect.isEmpty) path.addRRect(rrect);
266 | }
267 | return path;
268 | }
269 |
270 | Path buildDPath(String argD, {Path? path}) {
271 | if (videoItem.pathCache[argD] != null) {
272 | return videoItem.pathCache[argD]!;
273 | }
274 | path ??= Path();
275 | final d = argD.replaceAllMapped(RegExp('([a-df-zA-Z])'), (match) {
276 | return "|||${match.group(1)} ";
277 | }).replaceAll(RegExp(","), " ");
278 | var currentPointX = 0.0;
279 | var currentPointY = 0.0;
280 | double? currentPointX1;
281 | double? currentPointY1;
282 | double? currentPointX2;
283 | double? currentPointY2;
284 | d.split("|||").forEach((segment) {
285 | if (segment.isEmpty) {
286 | return;
287 | }
288 | final firstLetter = segment.substring(0, 1);
289 | if (_validMethods.contains(firstLetter)) {
290 | final args = segment.substring(1).trim().split(" ");
291 | if (firstLetter == "M") {
292 | currentPointX = double.parse(args[0]);
293 | currentPointY = double.parse(args[1]);
294 | path!.moveTo(currentPointX, currentPointY);
295 | } else if (firstLetter == "m") {
296 | currentPointX += double.parse(args[0]);
297 | currentPointY += double.parse(args[1]);
298 | path!.moveTo(currentPointX, currentPointY);
299 | } else if (firstLetter == "L") {
300 | currentPointX = double.parse(args[0]);
301 | currentPointY = double.parse(args[1]);
302 | path!.lineTo(currentPointX, currentPointY);
303 | } else if (firstLetter == "l") {
304 | currentPointX += double.parse(args[0]);
305 | currentPointY += double.parse(args[1]);
306 | path!.lineTo(currentPointX, currentPointY);
307 | } else if (firstLetter == "H") {
308 | currentPointX = double.parse(args[0]);
309 | path!.lineTo(currentPointX, currentPointY);
310 | } else if (firstLetter == "h") {
311 | currentPointX += double.parse(args[0]);
312 | path!.lineTo(currentPointX, currentPointY);
313 | } else if (firstLetter == "V") {
314 | currentPointY = double.parse(args[0]);
315 | path!.lineTo(currentPointX, currentPointY);
316 | } else if (firstLetter == "v") {
317 | currentPointY += double.parse(args[0]);
318 | path!.lineTo(currentPointX, currentPointY);
319 | } else if (firstLetter == "C") {
320 | currentPointX1 = double.parse(args[0]);
321 | currentPointY1 = double.parse(args[1]);
322 | currentPointX2 = double.parse(args[2]);
323 | currentPointY2 = double.parse(args[3]);
324 | currentPointX = double.parse(args[4]);
325 | currentPointY = double.parse(args[5]);
326 | path!.cubicTo(
327 | currentPointX1!,
328 | currentPointY1!,
329 | currentPointX2!,
330 | currentPointY2!,
331 | currentPointX,
332 | currentPointY,
333 | );
334 | } else if (firstLetter == "c") {
335 | currentPointX1 = currentPointX + double.parse(args[0]);
336 | currentPointY1 = currentPointY + double.parse(args[1]);
337 | currentPointX2 = currentPointX + double.parse(args[2]);
338 | currentPointY2 = currentPointY + double.parse(args[3]);
339 | currentPointX += double.parse(args[4]);
340 | currentPointY += double.parse(args[5]);
341 | path!.cubicTo(
342 | currentPointX1!,
343 | currentPointY1!,
344 | currentPointX2!,
345 | currentPointY2!,
346 | currentPointX,
347 | currentPointY,
348 | );
349 | } else if (firstLetter == "S") {
350 | if (currentPointX1 != null &&
351 | currentPointY1 != null &&
352 | currentPointX2 != null &&
353 | currentPointY2 != null) {
354 | currentPointX1 = currentPointX - currentPointX2! + currentPointX;
355 | currentPointY1 = currentPointY - currentPointY2! + currentPointY;
356 | currentPointX2 = double.parse(args[0]);
357 | currentPointY2 = double.parse(args[1]);
358 | currentPointX = double.parse(args[2]);
359 | currentPointY = double.parse(args[3]);
360 | path!.cubicTo(
361 | currentPointX1!,
362 | currentPointY1!,
363 | currentPointX2!,
364 | currentPointY2!,
365 | currentPointX,
366 | currentPointY,
367 | );
368 | } else {
369 | currentPointX1 = double.parse(args[0]);
370 | currentPointY1 = double.parse(args[1]);
371 | currentPointX = double.parse(args[2]);
372 | currentPointY = double.parse(args[3]);
373 | path!.quadraticBezierTo(
374 | currentPointX1!, currentPointY1!, currentPointX, currentPointY);
375 | }
376 | } else if (firstLetter == "s") {
377 | if (currentPointX1 != null &&
378 | currentPointY1 != null &&
379 | currentPointX2 != null &&
380 | currentPointY2 != null) {
381 | currentPointX1 = currentPointX - currentPointX2! + currentPointX;
382 | currentPointY1 = currentPointY - currentPointY2! + currentPointY;
383 | currentPointX2 = currentPointX + double.parse(args[0]);
384 | currentPointY2 = currentPointY + double.parse(args[1]);
385 | currentPointX += double.parse(args[2]);
386 | currentPointY += double.parse(args[3]);
387 | path!.cubicTo(
388 | currentPointX1!,
389 | currentPointY1!,
390 | currentPointX2!,
391 | currentPointY2!,
392 | currentPointX,
393 | currentPointY,
394 | );
395 | } else {
396 | currentPointX1 = currentPointX + double.parse(args[0]);
397 | currentPointY1 = currentPointY + double.parse(args[1]);
398 | currentPointX += double.parse(args[2]);
399 | currentPointY += double.parse(args[3]);
400 | path!.quadraticBezierTo(
401 | currentPointX1!,
402 | currentPointY1!,
403 | currentPointX,
404 | currentPointY,
405 | );
406 | }
407 | } else if (firstLetter == "Q") {
408 | currentPointX1 = double.parse(args[0]);
409 | currentPointY1 = double.parse(args[1]);
410 | currentPointX = double.parse(args[2]);
411 | currentPointY = double.parse(args[3]);
412 | path!.quadraticBezierTo(
413 | currentPointX1!, currentPointY1!, currentPointX, currentPointY);
414 | } else if (firstLetter == "q") {
415 | currentPointX1 = currentPointX + double.parse(args[0]);
416 | currentPointY1 = currentPointY + double.parse(args[1]);
417 | currentPointX += double.parse(args[2]);
418 | currentPointY += double.parse(args[3]);
419 | path!.quadraticBezierTo(
420 | currentPointX1!,
421 | currentPointY1!,
422 | currentPointX,
423 | currentPointY,
424 | );
425 | } else if (firstLetter == "Z" || firstLetter == "z") {
426 | path!.close();
427 | }
428 | }
429 | videoItem.pathCache[argD] = path!;
430 | });
431 | return path;
432 | }
433 |
434 | void drawTextOnBitmap(
435 | Canvas canvas, String imageKey, Rect frameRect, int frameAlpha) {
436 | var dynamicText = videoItem.dynamicItem.dynamicText;
437 | if (dynamicText.isEmpty) return;
438 | if (dynamicText[imageKey] == null) return;
439 |
440 | TextPainter? textPainter = dynamicText[imageKey];
441 |
442 | textPainter?.paint(
443 | canvas,
444 | Offset(
445 | (frameRect.width - textPainter.width) / 2.0,
446 | (frameRect.height - textPainter.height) / 2.0,
447 | ),
448 | );
449 | }
450 |
451 | @override
452 | bool shouldRepaint(_SVGAPainter oldDelegate) {
453 | if (controller._canvasNeedsClear == true) {
454 | return true;
455 | }
456 |
457 | return !(oldDelegate.controller == controller &&
458 | oldDelegate.controller.videoItem == controller.videoItem &&
459 | oldDelegate.fit == fit &&
460 | oldDelegate.filterQuality == filterQuality &&
461 | oldDelegate.clipRect == clipRect);
462 | }
463 | }
464 |
--------------------------------------------------------------------------------
/lib/parser.dart:
--------------------------------------------------------------------------------
1 | import 'dart:developer';
2 | import 'dart:ui' as ui;
3 | import 'dart:typed_data' show Uint8List;
4 | import 'package:flutter/foundation.dart';
5 | import 'package:flutter/painting.dart' show decodeImageFromList;
6 | import 'package:flutter/services.dart' show rootBundle;
7 | import 'package:http/http.dart' show get;
8 | import 'package:archive/archive.dart' as archive;
9 | // ignore: import_of_legacy_library_into_null_safe
10 | import 'proto/svga.pbserver.dart';
11 |
12 | const _filterKey = 'SVGAParser';
13 |
14 | /// You use SVGAParser to load and decode animation files.
15 | class SVGAParser {
16 | const SVGAParser();
17 | static const shared = SVGAParser();
18 |
19 | /// Download animation file from remote server, and decode it.
20 | Future decodeFromURL(String url) async {
21 | final response = await get(Uri.parse(url));
22 | return decodeFromBuffer(response.bodyBytes);
23 | }
24 |
25 | /// Download animation file from bundle assets, and decode it.
26 | Future decodeFromAssets(String path) async {
27 | return decodeFromBuffer((await rootBundle.load(path)).buffer.asUint8List());
28 | }
29 |
30 | /// Download animation file from buffer, and decode it.
31 | Future decodeFromBuffer(List bytes) {
32 | TimelineTask? timeline;
33 | if (!kReleaseMode) {
34 | timeline = TimelineTask(filterKey: _filterKey)
35 | ..start('DecodeFromBuffer', arguments: {'length': bytes.length});
36 | }
37 | final inflatedBytes = archive.ZLibDecoder().decodeBytes(bytes);
38 | if (timeline != null) {
39 | timeline.instant('MovieEntity.fromBuffer()',
40 | arguments: {'inflatedLength': inflatedBytes.length});
41 | }
42 | final movie = MovieEntity.fromBuffer(inflatedBytes);
43 | if (timeline != null) {
44 | timeline.instant('prepareResources()',
45 | arguments: {'images': movie.images.keys.join(',')});
46 | }
47 | return _prepareResources(
48 | _processShapeItems(movie),
49 | timeline: timeline,
50 | ).whenComplete(() {
51 | if (timeline != null) timeline.finish();
52 | });
53 | }
54 |
55 | MovieEntity _processShapeItems(MovieEntity movieItem) {
56 | movieItem.sprites.forEach((sprite) {
57 | List? lastShape;
58 | sprite.frames.forEach((frame) {
59 | if (frame.shapes.isNotEmpty && frame.shapes.length > 0) {
60 | if (frame.shapes[0].type == ShapeEntity_ShapeType.KEEP &&
61 | lastShape != null) {
62 | frame.shapes = lastShape;
63 | } else if (frame.shapes.isNotEmpty == true) {
64 | lastShape = frame.shapes;
65 | }
66 | }
67 | });
68 | });
69 | return movieItem;
70 | }
71 |
72 | Future _prepareResources(MovieEntity movieItem,
73 | {TimelineTask? timeline}) {
74 | final images = movieItem.images;
75 | if (images.isEmpty) return Future.value(movieItem);
76 | return Future.wait(images.entries.map((item) async {
77 | // result null means a decoding error occurred
78 | final decodeImage = await _decodeImageItem(
79 | item.key, Uint8List.fromList(item.value),
80 | timeline: timeline);
81 | if (decodeImage != null) {
82 | movieItem.bitmapCache[item.key] = decodeImage;
83 | }
84 | })).then((_) => movieItem);
85 | }
86 |
87 | Future _decodeImageItem(String key, Uint8List bytes,
88 | {TimelineTask? timeline}) async {
89 | TimelineTask? task;
90 | if (!kReleaseMode) {
91 | task = TimelineTask(filterKey: _filterKey, parent: timeline)
92 | ..start('DecodeImage', arguments: {'key': key, 'length': bytes.length});
93 | }
94 | try {
95 | final image = await decodeImageFromList(bytes);
96 | if (task != null) {
97 | task.finish(
98 | arguments: {'imageSize': '${image.width}x${image.height}'},
99 | );
100 | }
101 | return image;
102 | } catch (e, stack) {
103 | if (task != null) {
104 | task.finish(arguments: {'error': '$e', 'stack': '$stack'});
105 | }
106 | assert(() {
107 | FlutterError.reportError(FlutterErrorDetails(
108 | exception: e,
109 | stack: stack,
110 | library: 'svgaplayer',
111 | context: ErrorDescription('during prepare resource'),
112 | informationCollector: () sync* {
113 | yield ErrorSummary('Decoding image failed.');
114 | },
115 | ));
116 | return true;
117 | }());
118 | return null;
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/lib/player.dart:
--------------------------------------------------------------------------------
1 | library svgaplayer_flutter_player;
2 |
3 | import 'dart:math';
4 | import 'package:flutter/rendering.dart';
5 | import 'package:flutter/widgets.dart';
6 | // ignore: import_of_legacy_library_into_null_safe
7 | import 'package:svgaplayer_flutter/proto/svga.pb.dart';
8 | // ignore: import_of_legacy_library_into_null_safe
9 | import 'proto/svga.pbserver.dart';
10 | import 'dart:typed_data';
11 | import 'package:path_drawing/path_drawing.dart';
12 | import 'parser.dart';
13 | part 'painter.dart';
14 | part 'simple_player.dart';
15 |
16 | class SVGAImage extends StatefulWidget {
17 | final SVGAAnimationController _controller;
18 | final BoxFit fit;
19 | final bool clearsAfterStop;
20 |
21 | /// Used to set the filterQuality of drawing the images inside SVGA.
22 | ///
23 | /// Defaults to [FilterQuality.low]
24 | final FilterQuality filterQuality;
25 |
26 | /// If `true`, the SVGA painter may draw beyond the expected canvas bounds
27 | /// and cause additional memory overhead.
28 | ///
29 | /// For backwards compatibility, defaults to `null`,
30 | /// which means allow drawing to overflow canvas bounds.
31 | final bool? allowDrawingOverflow;
32 |
33 | /// If `null`, the viewbox size of [MovieEntity] will be use.
34 | ///
35 | /// Defaults to null.
36 | final Size? preferredSize;
37 | const SVGAImage(
38 | this._controller, {
39 | Key? key,
40 | this.fit = BoxFit.contain,
41 | this.filterQuality = FilterQuality.low,
42 | this.allowDrawingOverflow,
43 | this.clearsAfterStop = true,
44 | this.preferredSize,
45 | }) : super(key: key);
46 |
47 | @override
48 | State createState() => _SVGAImageState();
49 |
50 | @override
51 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
52 | super.debugFillProperties(properties);
53 | properties.add(DiagnosticsProperty('controller', _controller));
54 | }
55 | }
56 |
57 | class SVGAAnimationController extends AnimationController {
58 | MovieEntity? _videoItem;
59 | bool _canvasNeedsClear = false;
60 |
61 | SVGAAnimationController({
62 | required TickerProvider vsync,
63 | }) : super(vsync: vsync, duration: Duration.zero);
64 |
65 | set videoItem(MovieEntity? value) {
66 | assert(!_isDisposed, '$this has been disposed!');
67 | if (_isDisposed) return;
68 | if (isAnimating) {
69 | stop();
70 | }
71 | if (value == null) {
72 | clear();
73 | }
74 | if (_videoItem != null && _videoItem!.autorelease) {
75 | _videoItem!.dispose();
76 | }
77 | _videoItem = value;
78 | if (value != null) {
79 | final movieParams = value.params;
80 | assert(
81 | movieParams.viewBoxWidth >= 0 &&
82 | movieParams.viewBoxHeight >= 0 &&
83 | movieParams.frames >= 1,
84 | "Invalid SVGA file!");
85 | int fps = movieParams.fps;
86 | // avoid dividing by 0, use 20 by default
87 | // see https://github.com/svga/SVGAPlayer-Web/blob/1c5711db068a25006316f9890b11d6666d531c39/src/videoEntity.js#L51
88 | if (fps == 0) fps = 20;
89 | duration =
90 | Duration(milliseconds: (movieParams.frames / fps * 1000).toInt());
91 | } else {
92 | duration = Duration.zero;
93 | }
94 | // reset progress after videoitem changed
95 | reset();
96 | }
97 |
98 | MovieEntity? get videoItem => _videoItem;
99 |
100 | /// Current drawing frame index of [videoItem], returns 0 if [videoItem] is null.
101 | int get currentFrame {
102 | final videoItem = _videoItem;
103 | if (videoItem == null) return 0;
104 | return min(
105 | videoItem.params.frames - 1,
106 | max(0, (videoItem.params.frames.toDouble() * value).toInt()),
107 | );
108 | }
109 |
110 | /// Total frames of [videoItem], returns 0 if [videoItem] is null.
111 | int get frames {
112 | final videoItem = _videoItem;
113 | if (videoItem == null) return 0;
114 | return videoItem.params.frames;
115 | }
116 |
117 | /// mark [_SVGAPainter] needs clear
118 | void clear() {
119 | _canvasNeedsClear = true;
120 | if (!_isDisposed) notifyListeners();
121 | }
122 |
123 | @override
124 | TickerFuture forward({double? from}) {
125 | assert(_videoItem != null,
126 | 'SVGAAnimationController.forward() called after dispose()?');
127 | return super.forward(from: from);
128 | }
129 |
130 | bool _isDisposed = false;
131 | @override
132 | void dispose() {
133 | // auto dispose _videoItem when set null
134 | videoItem = null;
135 | _isDisposed = true;
136 | super.dispose();
137 | }
138 | }
139 |
140 | class _SVGAImageState extends State {
141 | MovieEntity? video;
142 | @override
143 | void initState() {
144 | super.initState();
145 | video = widget._controller.videoItem;
146 | widget._controller.addListener(_handleChange);
147 | widget._controller.addStatusListener(_handleStatusChange);
148 | }
149 |
150 | @override
151 | void didUpdateWidget(SVGAImage oldWidget) {
152 | super.didUpdateWidget(oldWidget);
153 | if (oldWidget._controller != widget._controller) {
154 | oldWidget._controller.removeListener(_handleChange);
155 | oldWidget._controller.removeStatusListener(_handleStatusChange);
156 | video = widget._controller.videoItem;
157 | widget._controller.addListener(_handleChange);
158 | widget._controller.addStatusListener(_handleStatusChange);
159 | }
160 | }
161 |
162 | void _handleChange() {
163 | if (mounted &&
164 | !widget._controller._isDisposed &&
165 | video != widget._controller.videoItem) {
166 | setState(() {
167 | // rebuild
168 | video = widget._controller.videoItem;
169 | });
170 | }
171 | }
172 |
173 | void _handleStatusChange(AnimationStatus status) {
174 | if (status == AnimationStatus.completed && widget.clearsAfterStop) {
175 | widget._controller.clear();
176 | }
177 | }
178 |
179 | @override
180 | void dispose() {
181 | video = null;
182 | widget._controller.removeListener(_handleChange);
183 | widget._controller.removeStatusListener(_handleStatusChange);
184 | super.dispose();
185 | }
186 |
187 | @override
188 | Widget build(BuildContext context) {
189 | final video = this.video;
190 | final Size viewBoxSize;
191 | if (video == null || !video.isInitialized()) {
192 | viewBoxSize = Size.zero;
193 | } else {
194 | viewBoxSize = Size(video.params.viewBoxWidth, video.params.viewBoxHeight);
195 | }
196 | if (viewBoxSize.isEmpty) {
197 | return const SizedBox.shrink();
198 | }
199 | // sugguest the size of CustomPaint
200 | Size preferredSize = viewBoxSize;
201 | if (widget.preferredSize != null) {
202 | preferredSize =
203 | BoxConstraints.tight(widget.preferredSize!).constrain(viewBoxSize);
204 | }
205 | return IgnorePointer(
206 | child: CustomPaint(
207 | painter: _SVGAPainter(
208 | // _SVGAPainter will auto repaint on _controller animating
209 | widget._controller,
210 | fit: widget.fit,
211 | filterQuality: widget.filterQuality,
212 | // default is allowing overflow for backward compatibility
213 | clipRect: widget.allowDrawingOverflow == false,
214 | ),
215 | size: preferredSize,
216 | ),
217 | );
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/lib/proto/svga.pbenum.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: svga.proto
4 | //
5 | // @dart = 2.12
6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
7 |
8 | // ignore_for_file: UNDEFINED_SHOWN_NAME
9 | import 'dart:core' as $core;
10 | import 'package:protobuf/protobuf.dart' as $pb;
11 |
12 | class ShapeEntity_ShapeType extends $pb.ProtobufEnum {
13 | static const ShapeEntity_ShapeType SHAPE = ShapeEntity_ShapeType._(
14 | 0,
15 | const $core.bool.fromEnvironment('protobuf.omit_enum_names')
16 | ? ''
17 | : 'SHAPE');
18 | static const ShapeEntity_ShapeType RECT = ShapeEntity_ShapeType._(
19 | 1,
20 | const $core.bool.fromEnvironment('protobuf.omit_enum_names')
21 | ? ''
22 | : 'RECT');
23 | static const ShapeEntity_ShapeType ELLIPSE = ShapeEntity_ShapeType._(
24 | 2,
25 | const $core.bool.fromEnvironment('protobuf.omit_enum_names')
26 | ? ''
27 | : 'ELLIPSE');
28 | static const ShapeEntity_ShapeType KEEP = ShapeEntity_ShapeType._(
29 | 3,
30 | const $core.bool.fromEnvironment('protobuf.omit_enum_names')
31 | ? ''
32 | : 'KEEP');
33 |
34 | static const $core.List values =
35 | [
36 | SHAPE,
37 | RECT,
38 | ELLIPSE,
39 | KEEP,
40 | ];
41 |
42 | static final $core.Map<$core.int, ShapeEntity_ShapeType> _byValue =
43 | $pb.ProtobufEnum.initByValue(values);
44 | static ShapeEntity_ShapeType? valueOf($core.int value) => _byValue[value];
45 |
46 | const ShapeEntity_ShapeType._($core.int v, $core.String n) : super(v, n);
47 | }
48 |
49 | class ShapeEntity_ShapeStyle_LineCap extends $pb.ProtobufEnum {
50 | static const ShapeEntity_ShapeStyle_LineCap LineCap_BUTT =
51 | ShapeEntity_ShapeStyle_LineCap._(
52 | 0,
53 | const $core.bool.fromEnvironment('protobuf.omit_enum_names')
54 | ? ''
55 | : 'LineCap_BUTT');
56 | static const ShapeEntity_ShapeStyle_LineCap LineCap_ROUND =
57 | ShapeEntity_ShapeStyle_LineCap._(
58 | 1,
59 | const $core.bool.fromEnvironment('protobuf.omit_enum_names')
60 | ? ''
61 | : 'LineCap_ROUND');
62 | static const ShapeEntity_ShapeStyle_LineCap LineCap_SQUARE =
63 | ShapeEntity_ShapeStyle_LineCap._(
64 | 2,
65 | const $core.bool.fromEnvironment('protobuf.omit_enum_names')
66 | ? ''
67 | : 'LineCap_SQUARE');
68 |
69 | static const $core.List values =
70 | [
71 | LineCap_BUTT,
72 | LineCap_ROUND,
73 | LineCap_SQUARE,
74 | ];
75 |
76 | static final $core.Map<$core.int, ShapeEntity_ShapeStyle_LineCap> _byValue =
77 | $pb.ProtobufEnum.initByValue(values);
78 | static ShapeEntity_ShapeStyle_LineCap? valueOf($core.int value) =>
79 | _byValue[value];
80 |
81 | const ShapeEntity_ShapeStyle_LineCap._($core.int v, $core.String n)
82 | : super(v, n);
83 | }
84 |
85 | class ShapeEntity_ShapeStyle_LineJoin extends $pb.ProtobufEnum {
86 | static const ShapeEntity_ShapeStyle_LineJoin LineJoin_MITER =
87 | ShapeEntity_ShapeStyle_LineJoin._(
88 | 0,
89 | const $core.bool.fromEnvironment('protobuf.omit_enum_names')
90 | ? ''
91 | : 'LineJoin_MITER');
92 | static const ShapeEntity_ShapeStyle_LineJoin LineJoin_ROUND =
93 | ShapeEntity_ShapeStyle_LineJoin._(
94 | 1,
95 | const $core.bool.fromEnvironment('protobuf.omit_enum_names')
96 | ? ''
97 | : 'LineJoin_ROUND');
98 | static const ShapeEntity_ShapeStyle_LineJoin LineJoin_BEVEL =
99 | ShapeEntity_ShapeStyle_LineJoin._(
100 | 2,
101 | const $core.bool.fromEnvironment('protobuf.omit_enum_names')
102 | ? ''
103 | : 'LineJoin_BEVEL');
104 |
105 | static const $core.List values =
106 | [
107 | LineJoin_MITER,
108 | LineJoin_ROUND,
109 | LineJoin_BEVEL,
110 | ];
111 |
112 | static final $core.Map<$core.int, ShapeEntity_ShapeStyle_LineJoin> _byValue =
113 | $pb.ProtobufEnum.initByValue(values);
114 | static ShapeEntity_ShapeStyle_LineJoin? valueOf($core.int value) =>
115 | _byValue[value];
116 |
117 | const ShapeEntity_ShapeStyle_LineJoin._($core.int v, $core.String n)
118 | : super(v, n);
119 | }
120 |
--------------------------------------------------------------------------------
/lib/proto/svga.pbjson.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: svga.proto
4 | //
5 | // @dart = 2.12
6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
7 |
8 | import 'dart:core' as $core;
9 | import 'dart:convert' as $convert;
10 | import 'dart:typed_data' as $typed_data;
11 |
12 | @$core.Deprecated('Use movieParamsDescriptor instead')
13 | const MovieParams$json = const {
14 | '1': 'MovieParams',
15 | '2': const [
16 | const {'1': 'viewBoxWidth', '3': 1, '4': 1, '5': 2, '10': 'viewBoxWidth'},
17 | const {'1': 'viewBoxHeight', '3': 2, '4': 1, '5': 2, '10': 'viewBoxHeight'},
18 | const {'1': 'fps', '3': 3, '4': 1, '5': 5, '10': 'fps'},
19 | const {'1': 'frames', '3': 4, '4': 1, '5': 5, '10': 'frames'},
20 | ],
21 | };
22 |
23 | /// Descriptor for `MovieParams`. Decode as a `google.protobuf.DescriptorProto`.
24 | final $typed_data.Uint8List movieParamsDescriptor = $convert.base64Decode(
25 | 'CgtNb3ZpZVBhcmFtcxIiCgx2aWV3Qm94V2lkdGgYASABKAJSDHZpZXdCb3hXaWR0aBIkCg12aWV3Qm94SGVpZ2h0GAIgASgCUg12aWV3Qm94SGVpZ2h0EhAKA2ZwcxgDIAEoBVIDZnBzEhYKBmZyYW1lcxgEIAEoBVIGZnJhbWVz');
26 | @$core.Deprecated('Use spriteEntityDescriptor instead')
27 | const SpriteEntity$json = const {
28 | '1': 'SpriteEntity',
29 | '2': const [
30 | const {'1': 'imageKey', '3': 1, '4': 1, '5': 9, '10': 'imageKey'},
31 | const {
32 | '1': 'frames',
33 | '3': 2,
34 | '4': 3,
35 | '5': 11,
36 | '6': '.com.opensource.svga.FrameEntity',
37 | '10': 'frames'
38 | },
39 | const {'1': 'matteKey', '3': 3, '4': 1, '5': 9, '10': 'matteKey'},
40 | ],
41 | };
42 |
43 | /// Descriptor for `SpriteEntity`. Decode as a `google.protobuf.DescriptorProto`.
44 | final $typed_data.Uint8List spriteEntityDescriptor = $convert.base64Decode(
45 | 'CgxTcHJpdGVFbnRpdHkSGgoIaW1hZ2VLZXkYASABKAlSCGltYWdlS2V5EjgKBmZyYW1lcxgCIAMoCzIgLmNvbS5vcGVuc291cmNlLnN2Z2EuRnJhbWVFbnRpdHlSBmZyYW1lcxIaCghtYXR0ZUtleRgDIAEoCVIIbWF0dGVLZXk=');
46 | @$core.Deprecated('Use audioEntityDescriptor instead')
47 | const AudioEntity$json = const {
48 | '1': 'AudioEntity',
49 | '2': const [
50 | const {'1': 'audioKey', '3': 1, '4': 1, '5': 9, '10': 'audioKey'},
51 | const {'1': 'startFrame', '3': 2, '4': 1, '5': 5, '10': 'startFrame'},
52 | const {'1': 'endFrame', '3': 3, '4': 1, '5': 5, '10': 'endFrame'},
53 | const {'1': 'startTime', '3': 4, '4': 1, '5': 5, '10': 'startTime'},
54 | const {'1': 'totalTime', '3': 5, '4': 1, '5': 5, '10': 'totalTime'},
55 | ],
56 | };
57 |
58 | /// Descriptor for `AudioEntity`. Decode as a `google.protobuf.DescriptorProto`.
59 | final $typed_data.Uint8List audioEntityDescriptor = $convert.base64Decode(
60 | 'CgtBdWRpb0VudGl0eRIaCghhdWRpb0tleRgBIAEoCVIIYXVkaW9LZXkSHgoKc3RhcnRGcmFtZRgCIAEoBVIKc3RhcnRGcmFtZRIaCghlbmRGcmFtZRgDIAEoBVIIZW5kRnJhbWUSHAoJc3RhcnRUaW1lGAQgASgFUglzdGFydFRpbWUSHAoJdG90YWxUaW1lGAUgASgFUgl0b3RhbFRpbWU=');
61 | @$core.Deprecated('Use layoutDescriptor instead')
62 | const Layout$json = const {
63 | '1': 'Layout',
64 | '2': const [
65 | const {'1': 'x', '3': 1, '4': 1, '5': 2, '10': 'x'},
66 | const {'1': 'y', '3': 2, '4': 1, '5': 2, '10': 'y'},
67 | const {'1': 'width', '3': 3, '4': 1, '5': 2, '10': 'width'},
68 | const {'1': 'height', '3': 4, '4': 1, '5': 2, '10': 'height'},
69 | ],
70 | };
71 |
72 | /// Descriptor for `Layout`. Decode as a `google.protobuf.DescriptorProto`.
73 | final $typed_data.Uint8List layoutDescriptor = $convert.base64Decode(
74 | 'CgZMYXlvdXQSDAoBeBgBIAEoAlIBeBIMCgF5GAIgASgCUgF5EhQKBXdpZHRoGAMgASgCUgV3aWR0aBIWCgZoZWlnaHQYBCABKAJSBmhlaWdodA==');
75 | @$core.Deprecated('Use transformDescriptor instead')
76 | const Transform$json = const {
77 | '1': 'Transform',
78 | '2': const [
79 | const {'1': 'a', '3': 1, '4': 1, '5': 2, '10': 'a'},
80 | const {'1': 'b', '3': 2, '4': 1, '5': 2, '10': 'b'},
81 | const {'1': 'c', '3': 3, '4': 1, '5': 2, '10': 'c'},
82 | const {'1': 'd', '3': 4, '4': 1, '5': 2, '10': 'd'},
83 | const {'1': 'tx', '3': 5, '4': 1, '5': 2, '10': 'tx'},
84 | const {'1': 'ty', '3': 6, '4': 1, '5': 2, '10': 'ty'},
85 | ],
86 | };
87 |
88 | /// Descriptor for `Transform`. Decode as a `google.protobuf.DescriptorProto`.
89 | final $typed_data.Uint8List transformDescriptor = $convert.base64Decode(
90 | 'CglUcmFuc2Zvcm0SDAoBYRgBIAEoAlIBYRIMCgFiGAIgASgCUgFiEgwKAWMYAyABKAJSAWMSDAoBZBgEIAEoAlIBZBIOCgJ0eBgFIAEoAlICdHgSDgoCdHkYBiABKAJSAnR5');
91 | @$core.Deprecated('Use shapeEntityDescriptor instead')
92 | const ShapeEntity$json = const {
93 | '1': 'ShapeEntity',
94 | '2': const [
95 | const {
96 | '1': 'type',
97 | '3': 1,
98 | '4': 1,
99 | '5': 14,
100 | '6': '.com.opensource.svga.ShapeEntity.ShapeType',
101 | '10': 'type'
102 | },
103 | const {
104 | '1': 'shape',
105 | '3': 2,
106 | '4': 1,
107 | '5': 11,
108 | '6': '.com.opensource.svga.ShapeEntity.ShapeArgs',
109 | '9': 0,
110 | '10': 'shape'
111 | },
112 | const {
113 | '1': 'rect',
114 | '3': 3,
115 | '4': 1,
116 | '5': 11,
117 | '6': '.com.opensource.svga.ShapeEntity.RectArgs',
118 | '9': 0,
119 | '10': 'rect'
120 | },
121 | const {
122 | '1': 'ellipse',
123 | '3': 4,
124 | '4': 1,
125 | '5': 11,
126 | '6': '.com.opensource.svga.ShapeEntity.EllipseArgs',
127 | '9': 0,
128 | '10': 'ellipse'
129 | },
130 | const {
131 | '1': 'styles',
132 | '3': 10,
133 | '4': 1,
134 | '5': 11,
135 | '6': '.com.opensource.svga.ShapeEntity.ShapeStyle',
136 | '10': 'styles'
137 | },
138 | const {
139 | '1': 'transform',
140 | '3': 11,
141 | '4': 1,
142 | '5': 11,
143 | '6': '.com.opensource.svga.Transform',
144 | '10': 'transform'
145 | },
146 | ],
147 | '3': const [
148 | ShapeEntity_ShapeArgs$json,
149 | ShapeEntity_RectArgs$json,
150 | ShapeEntity_EllipseArgs$json,
151 | ShapeEntity_ShapeStyle$json
152 | ],
153 | '4': const [ShapeEntity_ShapeType$json],
154 | '8': const [
155 | const {'1': 'args'},
156 | ],
157 | };
158 |
159 | @$core.Deprecated('Use shapeEntityDescriptor instead')
160 | const ShapeEntity_ShapeArgs$json = const {
161 | '1': 'ShapeArgs',
162 | '2': const [
163 | const {'1': 'd', '3': 1, '4': 1, '5': 9, '10': 'd'},
164 | ],
165 | };
166 |
167 | @$core.Deprecated('Use shapeEntityDescriptor instead')
168 | const ShapeEntity_RectArgs$json = const {
169 | '1': 'RectArgs',
170 | '2': const [
171 | const {'1': 'x', '3': 1, '4': 1, '5': 2, '10': 'x'},
172 | const {'1': 'y', '3': 2, '4': 1, '5': 2, '10': 'y'},
173 | const {'1': 'width', '3': 3, '4': 1, '5': 2, '10': 'width'},
174 | const {'1': 'height', '3': 4, '4': 1, '5': 2, '10': 'height'},
175 | const {'1': 'cornerRadius', '3': 5, '4': 1, '5': 2, '10': 'cornerRadius'},
176 | ],
177 | };
178 |
179 | @$core.Deprecated('Use shapeEntityDescriptor instead')
180 | const ShapeEntity_EllipseArgs$json = const {
181 | '1': 'EllipseArgs',
182 | '2': const [
183 | const {'1': 'x', '3': 1, '4': 1, '5': 2, '10': 'x'},
184 | const {'1': 'y', '3': 2, '4': 1, '5': 2, '10': 'y'},
185 | const {'1': 'radiusX', '3': 3, '4': 1, '5': 2, '10': 'radiusX'},
186 | const {'1': 'radiusY', '3': 4, '4': 1, '5': 2, '10': 'radiusY'},
187 | ],
188 | };
189 |
190 | @$core.Deprecated('Use shapeEntityDescriptor instead')
191 | const ShapeEntity_ShapeStyle$json = const {
192 | '1': 'ShapeStyle',
193 | '2': const [
194 | const {
195 | '1': 'fill',
196 | '3': 1,
197 | '4': 1,
198 | '5': 11,
199 | '6': '.com.opensource.svga.ShapeEntity.ShapeStyle.RGBAColor',
200 | '10': 'fill'
201 | },
202 | const {
203 | '1': 'stroke',
204 | '3': 2,
205 | '4': 1,
206 | '5': 11,
207 | '6': '.com.opensource.svga.ShapeEntity.ShapeStyle.RGBAColor',
208 | '10': 'stroke'
209 | },
210 | const {'1': 'strokeWidth', '3': 3, '4': 1, '5': 2, '10': 'strokeWidth'},
211 | const {
212 | '1': 'lineCap',
213 | '3': 4,
214 | '4': 1,
215 | '5': 14,
216 | '6': '.com.opensource.svga.ShapeEntity.ShapeStyle.LineCap',
217 | '10': 'lineCap'
218 | },
219 | const {
220 | '1': 'lineJoin',
221 | '3': 5,
222 | '4': 1,
223 | '5': 14,
224 | '6': '.com.opensource.svga.ShapeEntity.ShapeStyle.LineJoin',
225 | '10': 'lineJoin'
226 | },
227 | const {'1': 'miterLimit', '3': 6, '4': 1, '5': 2, '10': 'miterLimit'},
228 | const {'1': 'lineDashI', '3': 7, '4': 1, '5': 2, '10': 'lineDashI'},
229 | const {'1': 'lineDashII', '3': 8, '4': 1, '5': 2, '10': 'lineDashII'},
230 | const {'1': 'lineDashIII', '3': 9, '4': 1, '5': 2, '10': 'lineDashIII'},
231 | ],
232 | '3': const [ShapeEntity_ShapeStyle_RGBAColor$json],
233 | '4': const [
234 | ShapeEntity_ShapeStyle_LineCap$json,
235 | ShapeEntity_ShapeStyle_LineJoin$json
236 | ],
237 | };
238 |
239 | @$core.Deprecated('Use shapeEntityDescriptor instead')
240 | const ShapeEntity_ShapeStyle_RGBAColor$json = const {
241 | '1': 'RGBAColor',
242 | '2': const [
243 | const {'1': 'r', '3': 1, '4': 1, '5': 2, '10': 'r'},
244 | const {'1': 'g', '3': 2, '4': 1, '5': 2, '10': 'g'},
245 | const {'1': 'b', '3': 3, '4': 1, '5': 2, '10': 'b'},
246 | const {'1': 'a', '3': 4, '4': 1, '5': 2, '10': 'a'},
247 | ],
248 | };
249 |
250 | @$core.Deprecated('Use shapeEntityDescriptor instead')
251 | const ShapeEntity_ShapeStyle_LineCap$json = const {
252 | '1': 'LineCap',
253 | '2': const [
254 | const {'1': 'LineCap_BUTT', '2': 0},
255 | const {'1': 'LineCap_ROUND', '2': 1},
256 | const {'1': 'LineCap_SQUARE', '2': 2},
257 | ],
258 | };
259 |
260 | @$core.Deprecated('Use shapeEntityDescriptor instead')
261 | const ShapeEntity_ShapeStyle_LineJoin$json = const {
262 | '1': 'LineJoin',
263 | '2': const [
264 | const {'1': 'LineJoin_MITER', '2': 0},
265 | const {'1': 'LineJoin_ROUND', '2': 1},
266 | const {'1': 'LineJoin_BEVEL', '2': 2},
267 | ],
268 | };
269 |
270 | @$core.Deprecated('Use shapeEntityDescriptor instead')
271 | const ShapeEntity_ShapeType$json = const {
272 | '1': 'ShapeType',
273 | '2': const [
274 | const {'1': 'SHAPE', '2': 0},
275 | const {'1': 'RECT', '2': 1},
276 | const {'1': 'ELLIPSE', '2': 2},
277 | const {'1': 'KEEP', '2': 3},
278 | ],
279 | };
280 |
281 | /// Descriptor for `ShapeEntity`. Decode as a `google.protobuf.DescriptorProto`.
282 | final $typed_data.Uint8List shapeEntityDescriptor = $convert.base64Decode(
283 | 'CgtTaGFwZUVudGl0eRI+CgR0eXBlGAEgASgOMiouY29tLm9wZW5zb3VyY2Uuc3ZnYS5TaGFwZUVudGl0eS5TaGFwZVR5cGVSBHR5cGUSQgoFc2hhcGUYAiABKAsyKi5jb20ub3BlbnNvdXJjZS5zdmdhLlNoYXBlRW50aXR5LlNoYXBlQXJnc0gAUgVzaGFwZRI/CgRyZWN0GAMgASgLMikuY29tLm9wZW5zb3VyY2Uuc3ZnYS5TaGFwZUVudGl0eS5SZWN0QXJnc0gAUgRyZWN0EkgKB2VsbGlwc2UYBCABKAsyLC5jb20ub3BlbnNvdXJjZS5zdmdhLlNoYXBlRW50aXR5LkVsbGlwc2VBcmdzSABSB2VsbGlwc2USQwoGc3R5bGVzGAogASgLMisuY29tLm9wZW5zb3VyY2Uuc3ZnYS5TaGFwZUVudGl0eS5TaGFwZVN0eWxlUgZzdHlsZXMSPAoJdHJhbnNmb3JtGAsgASgLMh4uY29tLm9wZW5zb3VyY2Uuc3ZnYS5UcmFuc2Zvcm1SCXRyYW5zZm9ybRoZCglTaGFwZUFyZ3MSDAoBZBgBIAEoCVIBZBp4CghSZWN0QXJncxIMCgF4GAEgASgCUgF4EgwKAXkYAiABKAJSAXkSFAoFd2lkdGgYAyABKAJSBXdpZHRoEhYKBmhlaWdodBgEIAEoAlIGaGVpZ2h0EiIKDGNvcm5lclJhZGl1cxgFIAEoAlIMY29ybmVyUmFkaXVzGl0KC0VsbGlwc2VBcmdzEgwKAXgYASABKAJSAXgSDAoBeRgCIAEoAlIBeRIYCgdyYWRpdXNYGAMgASgCUgdyYWRpdXNYEhgKB3JhZGl1c1kYBCABKAJSB3JhZGl1c1kaugUKClNoYXBlU3R5bGUSSQoEZmlsbBgBIAEoCzI1LmNvbS5vcGVuc291cmNlLnN2Z2EuU2hhcGVFbnRpdHkuU2hhcGVTdHlsZS5SR0JBQ29sb3JSBGZpbGwSTQoGc3Ryb2tlGAIgASgLMjUuY29tLm9wZW5zb3VyY2Uuc3ZnYS5TaGFwZUVudGl0eS5TaGFwZVN0eWxlLlJHQkFDb2xvclIGc3Ryb2tlEiAKC3N0cm9rZVdpZHRoGAMgASgCUgtzdHJva2VXaWR0aBJNCgdsaW5lQ2FwGAQgASgOMjMuY29tLm9wZW5zb3VyY2Uuc3ZnYS5TaGFwZUVudGl0eS5TaGFwZVN0eWxlLkxpbmVDYXBSB2xpbmVDYXASUAoIbGluZUpvaW4YBSABKA4yNC5jb20ub3BlbnNvdXJjZS5zdmdhLlNoYXBlRW50aXR5LlNoYXBlU3R5bGUuTGluZUpvaW5SCGxpbmVKb2luEh4KCm1pdGVyTGltaXQYBiABKAJSCm1pdGVyTGltaXQSHAoJbGluZURhc2hJGAcgASgCUglsaW5lRGFzaEkSHgoKbGluZURhc2hJSRgIIAEoAlIKbGluZURhc2hJSRIgCgtsaW5lRGFzaElJSRgJIAEoAlILbGluZURhc2hJSUkaQwoJUkdCQUNvbG9yEgwKAXIYASABKAJSAXISDAoBZxgCIAEoAlIBZxIMCgFiGAMgASgCUgFiEgwKAWEYBCABKAJSAWEiQgoHTGluZUNhcBIQCgxMaW5lQ2FwX0JVVFQQABIRCg1MaW5lQ2FwX1JPVU5EEAESEgoOTGluZUNhcF9TUVVBUkUQAiJGCghMaW5lSm9pbhISCg5MaW5lSm9pbl9NSVRFUhAAEhIKDkxpbmVKb2luX1JPVU5EEAESEgoOTGluZUpvaW5fQkVWRUwQAiI3CglTaGFwZVR5cGUSCQoFU0hBUEUQABIICgRSRUNUEAESCwoHRUxMSVBTRRACEggKBEtFRVAQA0IGCgRhcmdz');
284 | @$core.Deprecated('Use frameEntityDescriptor instead')
285 | const FrameEntity$json = const {
286 | '1': 'FrameEntity',
287 | '2': const [
288 | const {'1': 'alpha', '3': 1, '4': 1, '5': 2, '10': 'alpha'},
289 | const {
290 | '1': 'layout',
291 | '3': 2,
292 | '4': 1,
293 | '5': 11,
294 | '6': '.com.opensource.svga.Layout',
295 | '10': 'layout'
296 | },
297 | const {
298 | '1': 'transform',
299 | '3': 3,
300 | '4': 1,
301 | '5': 11,
302 | '6': '.com.opensource.svga.Transform',
303 | '10': 'transform'
304 | },
305 | const {'1': 'clipPath', '3': 4, '4': 1, '5': 9, '10': 'clipPath'},
306 | const {
307 | '1': 'shapes',
308 | '3': 5,
309 | '4': 3,
310 | '5': 11,
311 | '6': '.com.opensource.svga.ShapeEntity',
312 | '10': 'shapes'
313 | },
314 | ],
315 | };
316 |
317 | /// Descriptor for `FrameEntity`. Decode as a `google.protobuf.DescriptorProto`.
318 | final $typed_data.Uint8List frameEntityDescriptor = $convert.base64Decode(
319 | 'CgtGcmFtZUVudGl0eRIUCgVhbHBoYRgBIAEoAlIFYWxwaGESMwoGbGF5b3V0GAIgASgLMhsuY29tLm9wZW5zb3VyY2Uuc3ZnYS5MYXlvdXRSBmxheW91dBI8Cgl0cmFuc2Zvcm0YAyABKAsyHi5jb20ub3BlbnNvdXJjZS5zdmdhLlRyYW5zZm9ybVIJdHJhbnNmb3JtEhoKCGNsaXBQYXRoGAQgASgJUghjbGlwUGF0aBI4CgZzaGFwZXMYBSADKAsyIC5jb20ub3BlbnNvdXJjZS5zdmdhLlNoYXBlRW50aXR5UgZzaGFwZXM=');
320 | @$core.Deprecated('Use movieEntityDescriptor instead')
321 | const MovieEntity$json = const {
322 | '1': 'MovieEntity',
323 | '2': const [
324 | const {'1': 'version', '3': 1, '4': 1, '5': 9, '10': 'version'},
325 | const {
326 | '1': 'params',
327 | '3': 2,
328 | '4': 1,
329 | '5': 11,
330 | '6': '.com.opensource.svga.MovieParams',
331 | '10': 'params'
332 | },
333 | const {
334 | '1': 'images',
335 | '3': 3,
336 | '4': 3,
337 | '5': 11,
338 | '6': '.com.opensource.svga.MovieEntity.ImagesEntry',
339 | '10': 'images'
340 | },
341 | const {
342 | '1': 'sprites',
343 | '3': 4,
344 | '4': 3,
345 | '5': 11,
346 | '6': '.com.opensource.svga.SpriteEntity',
347 | '10': 'sprites'
348 | },
349 | const {
350 | '1': 'audios',
351 | '3': 5,
352 | '4': 3,
353 | '5': 11,
354 | '6': '.com.opensource.svga.AudioEntity',
355 | '10': 'audios'
356 | },
357 | ],
358 | '3': const [MovieEntity_ImagesEntry$json],
359 | };
360 |
361 | @$core.Deprecated('Use movieEntityDescriptor instead')
362 | const MovieEntity_ImagesEntry$json = const {
363 | '1': 'ImagesEntry',
364 | '2': const [
365 | const {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},
366 | const {'1': 'value', '3': 2, '4': 1, '5': 12, '10': 'value'},
367 | ],
368 | '7': const {'7': true},
369 | };
370 |
371 | /// Descriptor for `MovieEntity`. Decode as a `google.protobuf.DescriptorProto`.
372 | final $typed_data.Uint8List movieEntityDescriptor = $convert.base64Decode(
373 | 'CgtNb3ZpZUVudGl0eRIYCgd2ZXJzaW9uGAEgASgJUgd2ZXJzaW9uEjgKBnBhcmFtcxgCIAEoCzIgLmNvbS5vcGVuc291cmNlLnN2Z2EuTW92aWVQYXJhbXNSBnBhcmFtcxJECgZpbWFnZXMYAyADKAsyLC5jb20ub3BlbnNvdXJjZS5zdmdhLk1vdmllRW50aXR5LkltYWdlc0VudHJ5UgZpbWFnZXMSOwoHc3ByaXRlcxgEIAMoCzIhLmNvbS5vcGVuc291cmNlLnN2Z2EuU3ByaXRlRW50aXR5UgdzcHJpdGVzEjgKBmF1ZGlvcxgFIAMoCzIgLmNvbS5vcGVuc291cmNlLnN2Z2EuQXVkaW9FbnRpdHlSBmF1ZGlvcxo5CgtJbWFnZXNFbnRyeRIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1ZRgCIAEoDFIFdmFsdWU6AjgB');
374 |
--------------------------------------------------------------------------------
/lib/proto/svga.pbserver.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: svga.proto
4 | //
5 | // @dart = 2.12
6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
7 |
8 | export 'svga.pb.dart';
9 |
--------------------------------------------------------------------------------
/lib/simple_player.dart:
--------------------------------------------------------------------------------
1 | part of svgaplayer_flutter_player;
2 |
3 | class SVGASimpleImage extends StatefulWidget {
4 | final String? resUrl;
5 | final String? assetsName;
6 |
7 | const SVGASimpleImage({Key? key, this.resUrl, this.assetsName})
8 | : super(key: key);
9 |
10 | @override
11 | State createState() {
12 | return _SVGASimpleImageState();
13 | }
14 | }
15 |
16 | class _SVGASimpleImageState extends State
17 | with SingleTickerProviderStateMixin {
18 | SVGAAnimationController? animationController;
19 |
20 | @override
21 | void initState() {
22 | super.initState();
23 | animationController = SVGAAnimationController(vsync: this);
24 | _tryDecodeSvga();
25 | }
26 |
27 | @override
28 | void didUpdateWidget(covariant SVGASimpleImage oldWidget) {
29 | super.didUpdateWidget(oldWidget);
30 | if (oldWidget.resUrl != widget.resUrl || oldWidget.assetsName != widget.assetsName) {
31 | _tryDecodeSvga();
32 | }
33 | }
34 |
35 | @override
36 | Widget build(BuildContext context) {
37 | if (animationController == null) {
38 | return Container();
39 | }
40 | return SVGAImage(animationController!);
41 | }
42 |
43 | @override
44 | void dispose() {
45 | animationController?.dispose();
46 | animationController = null;
47 | super.dispose();
48 | }
49 |
50 | void _tryDecodeSvga() {
51 | Future decode;
52 | if (widget.resUrl != null) {
53 | decode = SVGAParser.shared.decodeFromURL(widget.resUrl!);
54 | } else if (widget.assetsName != null) {
55 | decode = SVGAParser.shared.decodeFromAssets(widget.assetsName!);
56 | } else {
57 | return;
58 | }
59 | decode.then((videoItem) {
60 | if (mounted && animationController != null) {
61 | animationController!
62 | ..videoItem = videoItem
63 | ..repeat();
64 | } else {
65 | videoItem.dispose();
66 | }
67 | }).catchError((e, stack) {
68 | FlutterError.reportError(FlutterErrorDetails(
69 | exception: e,
70 | stack: stack,
71 | library: 'svga library',
72 | informationCollector: () => [
73 | if (widget.resUrl != null) StringProperty('resUrl', widget.resUrl),
74 | if (widget.assetsName != null)
75 | StringProperty('assetsName', widget.assetsName),
76 | ],
77 | ));
78 | });
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/lib/svgaplayer_flutter.dart:
--------------------------------------------------------------------------------
1 | export 'parser.dart';
2 | export 'player.dart';
3 | export 'proto/svga.pb.dart' show MovieEntity, MovieParams, ShapeEntity, FrameEntity;
4 | export 'dynamic_entity.dart';
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.0.1"
3 | }
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | archive:
5 | dependency: "direct main"
6 | description:
7 | name: archive
8 | url: "https://pub.flutter-io.cn"
9 | source: hosted
10 | version: "3.1.2"
11 | async:
12 | dependency: transitive
13 | description:
14 | name: async
15 | url: "https://pub.flutter-io.cn"
16 | source: hosted
17 | version: "2.9.0"
18 | boolean_selector:
19 | dependency: transitive
20 | description:
21 | name: boolean_selector
22 | url: "https://pub.flutter-io.cn"
23 | source: hosted
24 | version: "2.1.0"
25 | characters:
26 | dependency: transitive
27 | description:
28 | name: characters
29 | url: "https://pub.flutter-io.cn"
30 | source: hosted
31 | version: "1.2.1"
32 | charcode:
33 | dependency: transitive
34 | description:
35 | name: charcode
36 | url: "https://pub.flutter-io.cn"
37 | source: hosted
38 | version: "1.3.1"
39 | clock:
40 | dependency: transitive
41 | description:
42 | name: clock
43 | url: "https://pub.flutter-io.cn"
44 | source: hosted
45 | version: "1.1.1"
46 | collection:
47 | dependency: transitive
48 | description:
49 | name: collection
50 | url: "https://pub.flutter-io.cn"
51 | source: hosted
52 | version: "1.16.0"
53 | crypto:
54 | dependency: transitive
55 | description:
56 | name: crypto
57 | url: "https://pub.flutter-io.cn"
58 | source: hosted
59 | version: "3.0.1"
60 | fake_async:
61 | dependency: transitive
62 | description:
63 | name: fake_async
64 | url: "https://pub.flutter-io.cn"
65 | source: hosted
66 | version: "1.3.1"
67 | fixnum:
68 | dependency: transitive
69 | description:
70 | name: fixnum
71 | url: "https://pub.flutter-io.cn"
72 | source: hosted
73 | version: "1.0.0"
74 | flutter:
75 | dependency: "direct main"
76 | description: flutter
77 | source: sdk
78 | version: "0.0.0"
79 | flutter_lints:
80 | dependency: "direct dev"
81 | description:
82 | name: flutter_lints
83 | url: "https://pub.flutter-io.cn"
84 | source: hosted
85 | version: "1.0.4"
86 | flutter_test:
87 | dependency: "direct dev"
88 | description: flutter
89 | source: sdk
90 | version: "0.0.0"
91 | http:
92 | dependency: "direct main"
93 | description:
94 | name: http
95 | url: "https://pub.flutter-io.cn"
96 | source: hosted
97 | version: "0.13.3"
98 | http_parser:
99 | dependency: transitive
100 | description:
101 | name: http_parser
102 | url: "https://pub.flutter-io.cn"
103 | source: hosted
104 | version: "4.0.0"
105 | lints:
106 | dependency: transitive
107 | description:
108 | name: lints
109 | url: "https://pub.flutter-io.cn"
110 | source: hosted
111 | version: "1.0.1"
112 | matcher:
113 | dependency: transitive
114 | description:
115 | name: matcher
116 | url: "https://pub.flutter-io.cn"
117 | source: hosted
118 | version: "0.12.12"
119 | material_color_utilities:
120 | dependency: transitive
121 | description:
122 | name: material_color_utilities
123 | url: "https://pub.flutter-io.cn"
124 | source: hosted
125 | version: "0.1.5"
126 | meta:
127 | dependency: transitive
128 | description:
129 | name: meta
130 | url: "https://pub.flutter-io.cn"
131 | source: hosted
132 | version: "1.8.0"
133 | path:
134 | dependency: transitive
135 | description:
136 | name: path
137 | url: "https://pub.flutter-io.cn"
138 | source: hosted
139 | version: "1.8.2"
140 | path_drawing:
141 | dependency: "direct main"
142 | description:
143 | name: path_drawing
144 | url: "https://pub.flutter-io.cn"
145 | source: hosted
146 | version: "1.0.1"
147 | path_parsing:
148 | dependency: transitive
149 | description:
150 | name: path_parsing
151 | url: "https://pub.flutter-io.cn"
152 | source: hosted
153 | version: "1.0.1"
154 | pedantic:
155 | dependency: transitive
156 | description:
157 | name: pedantic
158 | url: "https://pub.flutter-io.cn"
159 | source: hosted
160 | version: "1.11.0"
161 | protobuf:
162 | dependency: "direct main"
163 | description:
164 | name: protobuf
165 | url: "https://pub.flutter-io.cn"
166 | source: hosted
167 | version: "2.0.0"
168 | sky_engine:
169 | dependency: transitive
170 | description: flutter
171 | source: sdk
172 | version: "0.0.99"
173 | source_span:
174 | dependency: transitive
175 | description:
176 | name: source_span
177 | url: "https://pub.flutter-io.cn"
178 | source: hosted
179 | version: "1.9.0"
180 | stack_trace:
181 | dependency: transitive
182 | description:
183 | name: stack_trace
184 | url: "https://pub.flutter-io.cn"
185 | source: hosted
186 | version: "1.10.0"
187 | stream_channel:
188 | dependency: transitive
189 | description:
190 | name: stream_channel
191 | url: "https://pub.flutter-io.cn"
192 | source: hosted
193 | version: "2.1.0"
194 | string_scanner:
195 | dependency: transitive
196 | description:
197 | name: string_scanner
198 | url: "https://pub.flutter-io.cn"
199 | source: hosted
200 | version: "1.1.1"
201 | term_glyph:
202 | dependency: transitive
203 | description:
204 | name: term_glyph
205 | url: "https://pub.flutter-io.cn"
206 | source: hosted
207 | version: "1.2.1"
208 | test_api:
209 | dependency: transitive
210 | description:
211 | name: test_api
212 | url: "https://pub.flutter-io.cn"
213 | source: hosted
214 | version: "0.4.12"
215 | typed_data:
216 | dependency: transitive
217 | description:
218 | name: typed_data
219 | url: "https://pub.flutter-io.cn"
220 | source: hosted
221 | version: "1.3.0"
222 | vector_math:
223 | dependency: transitive
224 | description:
225 | name: vector_math
226 | url: "https://pub.flutter-io.cn"
227 | source: hosted
228 | version: "2.1.2"
229 | sdks:
230 | dart: ">=2.17.0-0 <3.0.0"
231 | flutter: ">=1.24.0-7.0"
232 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: svgaplayer_flutter
2 | description: The SVGAPlayer implementation of Flutter using CustomPainter.
3 | version: 2.2.0
4 | homepage: https://github.com/yyued/SVGAPlayer-Flutter
5 |
6 | environment:
7 | sdk: ">=2.12.0 <3.0.0"
8 |
9 | dependencies:
10 | flutter:
11 | sdk: flutter
12 | protobuf: ^2.0.0
13 | http: ^0.13.3
14 | path_drawing: ^1.0.0
15 | archive: ^3.1.2
16 |
17 | dev_dependencies:
18 | flutter_test:
19 | sdk: flutter
20 | flutter_lints: ^1.0.4
21 |
--------------------------------------------------------------------------------
/svgaplayer_flutter.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/test/svgaplayer_flutter_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 | import 'package:flutter_test/flutter_test.dart';
3 |
4 | void main() {
5 | const MethodChannel channel = MethodChannel('svgaplayer_flutter');
6 |
7 | setUp(() {
8 | channel.setMockMethodCallHandler((MethodCall methodCall) async {
9 | return '42';
10 | });
11 | });
12 |
13 | tearDown(() {
14 | channel.setMockMethodCallHandler(null);
15 | });
16 | }
17 |
--------------------------------------------------------------------------------