Compare commits

..

3 Commits

Author SHA1 Message Date
27b2ec471f Add errorBuilder 2020-10-12 22:07:03 +02:00
57faea6f5e Fill Performance Improvements and other fixes (#100)
This PR improves some fill performance issues I found with various Lottie animations.
I think the real issue comes down to the render performance of Path.addPath(). The performance issue happens in the Render thread and seems directly related to how large the animation is on-screen. Flutter might be caching pre-rendered textures and running out of memory.

I've changed how Path.addPath() is called and how the path is rendered for fill_content.dart and gradient_fill_content.dart.

Just as an example, the example/assets/Tests/bm.json animation gets ~60 fps with this fix, compared to 34-52 fps with the lottie-flutter 0.6.0 release. (This is on a Pixel 3 XL)

There are a couple of other changes:

- I fixed a bug with the casing of "weather" in pubspec.yaml. Without this fix, the examples don't build on Ubuntu Linux.
The debugging class MeanCalculator wasn't initializing its fields, causing a null pointer exception when debugging.
- I added antiAliasingSuggested to LottieDrawable to allow fill paints to be anti-aliased. It is off by default. It also provides some minor performance improvements without any noticeable loss in quality. It is only applied to fills right now.
- I added PathFactory to create Paths rather than just new-ing them. path_factory.dart allows you to switch out the normal Path creation with a debug logging implementation so you can see all of the Path calls that are performed during a frame. Just create a DebugPath in the factory rather than Path.
2020-09-10 14:18:56 +02:00
548c77dc45 Add FrameRate and improve performance (#93)
- Run the animation at the exported frame rate
- Wrap the animation in a RepaintBoundary
- Don't paint during "static" periods
2020-08-04 22:02:02 +02:00
127 changed files with 708 additions and 300 deletions

View File

@ -1,3 +1,14 @@
## [0.6.0]
- Runs the animation at the frame rate specified in the json file (ie. An animation encoded with a 20 FPS will only
be paint 20 times per seconds even though the AnimationController will invalidate the widget 60 times per seconds).
A new property `frameRate` allows to opt-out this behavior and have the widget to repaint at the device frame rate
(`FrameRate.max`).
- Automatically add a `RepaintBoundary` around the widget. Since `Lottie` animations are generally complex to paint, a
`RepaintBoundary` will separate the animation with the rest of the app and improve performance. A new property `addRepaintBoundary`
allows to opt-out this behavior.
- Fix a bug where we would call `markNeedPaint` when the animation was not changing. This removes unnecessary paints in
animations with static periods.
## [0.5.1] ## [0.5.1]
- Remove direct dependencies on dart:io to support Flutter Web - Remove direct dependencies on dart:io to support Flutter Web

View File

@ -17,7 +17,7 @@ This example shows how to display a Lottie animation in the simplest way.
The `Lottie` widget will load the json file and run the animation indefinitely. The `Lottie` widget will load the json file and run the animation indefinitely.
```dart ```dart
import 'example/lib/examples/main.dart'; import 'example/lib/main.dart';
``` ```
### Specify a custom `AnimationController` ### Specify a custom `AnimationController`

View File

@ -1,27 +0,0 @@
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView(
children: [
// Load a Lottie file from your assets
Lottie.asset('assets/LottieLogo1.json'),
// Load a Lottie file from a remote url
Lottie.network(
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json'),
// Load an animation and its images from a zip file
Lottie.asset('assets/lottiefiles/angel.zip'),
],
),
),
);
}
}

View File

@ -1,157 +1,24 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:lottie/lottie.dart'; import 'package:lottie/lottie.dart';
import 'src/all_files.g.dart';
void main() { void main() => runApp(MyApp());
Logger.root
..level = Level.ALL
..onRecord.listen(print);
Lottie.traceEnabled = true;
runApp(App());
}
class App extends StatelessWidget { class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
//showPerformanceOverlay: true,
home: Scaffold( home: Scaffold(
appBar: AppBar( body: ListView(
title: Text('Lottie Flutter'),
),
body: GridView.builder(
itemCount: files.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 4),
itemBuilder: (context, index) {
var assetName = files[index];
return GestureDetector(
child: _Item(
child: Lottie.asset(
assetName,
frameBuilder: (context, child, composition) {
return AnimatedOpacity(
child: child,
opacity: composition == null ? 0 : 1,
duration: const Duration(seconds: 1),
curve: Curves.easeOut,
);
},
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (context) => Detail(assetName)));
},
);
},
),
),
);
}
}
class _Item extends StatelessWidget {
final Widget child;
const _Item({Key key, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(10)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
offset: Offset(2, 2),
blurRadius: 5)
]),
child: child,
),
);
}
}
class Detail extends StatefulWidget {
final String assetName;
const Detail(this.assetName, {Key key}) : super(key: key);
@override
_DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> with TickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('${widget.assetName}'),
),
body: SingleChildScrollView(
child: Column(
children: [ children: [
Center( // Load a Lottie file from your assets
child: Lottie.asset( Lottie.asset('assets/LottieLogo1.json'),
widget.assetName,
controller: _controller, // Load a Lottie file from a remote url
onLoaded: (composition) { Lottie.network(
_controller.duration = composition.duration; 'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json'),
_controller.repeat();
}, // Load an animation and its images from a zip file
), Lottie.asset('assets/lottiefiles/angel.zip'),
),
AnimatedBuilder(
animation: _controller,
builder: (context, _) => Row(
children: <Widget>[
Expanded(
child: Slider(
value: _controller.value,
onChanged: (newValue) {
_controller.value = newValue;
},
),
),
IconButton(
icon: Icon(_controller.isAnimating
? Icons.stop
: Icons.play_arrow),
onPressed: () {
setState(() {
if (_controller.isAnimating) {
_controller.stop();
} else {
_controller.repeat();
}
});
},
),
],
),
),
], ],
), ),
), ),

160
example/lib/main_app.dart Normal file
View File

@ -0,0 +1,160 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:lottie/lottie.dart';
import 'src/all_files.g.dart';
void main() {
Logger.root
..level = Level.ALL
..onRecord.listen(print);
Lottie.traceEnabled = true;
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
//showPerformanceOverlay: true,
home: Scaffold(
appBar: AppBar(
title: Text('Lottie Flutter'),
),
body: GridView.builder(
itemCount: files.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 4),
itemBuilder: (context, index) {
var assetName = files[index];
return GestureDetector(
child: _Item(
child: Lottie.asset(
assetName,
frameBuilder: (context, child, composition) {
return AnimatedOpacity(
child: child,
opacity: composition == null ? 0 : 1,
duration: const Duration(seconds: 1),
curve: Curves.easeOut,
);
},
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (context) => Detail(assetName)));
},
);
},
),
),
);
}
}
class _Item extends StatelessWidget {
final Widget child;
const _Item({Key key, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(10)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
offset: Offset(2, 2),
blurRadius: 5)
]),
child: child,
),
);
}
}
class Detail extends StatefulWidget {
final String assetName;
const Detail(this.assetName, {Key key}) : super(key: key);
@override
_DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> with TickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('${widget.assetName}'),
),
body: SingleChildScrollView(
child: Column(
children: [
Center(
child: Lottie.asset(
widget.assetName,
controller: _controller,
onLoaded: (composition) {
_controller.duration = composition.duration;
_controller.repeat();
},
),
),
AnimatedBuilder(
animation: _controller,
builder: (context, _) => Row(
children: <Widget>[
Expanded(
child: Slider(
value: _controller.value,
onChanged: (newValue) {
_controller.value = newValue;
},
),
),
IconButton(
icon: Icon(_controller.isAnimating
? Icons.stop
: Icons.play_arrow),
onPressed: () {
setState(() {
if (_controller.isAnimating) {
_controller.stop();
} else {
_controller.repeat();
}
});
},
),
],
),
),
],
),
),
);
}
}

View File

@ -5,13 +5,13 @@ PODS:
- FlutterMacOS - FlutterMacOS
DEPENDENCIES: DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral/.symlinks/flutter/darwin-x64`) - FlutterMacOS (from `Flutter/ephemeral/.symlinks/flutter/darwin-x64-profile`)
- path_provider (from `Flutter/ephemeral/.symlinks/plugins/path_provider/macos`) - path_provider (from `Flutter/ephemeral/.symlinks/plugins/path_provider/macos`)
- path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`) - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
EXTERNAL SOURCES: EXTERNAL SOURCES:
FlutterMacOS: FlutterMacOS:
:path: Flutter/ephemeral/.symlinks/flutter/darwin-x64 :path: Flutter/ephemeral/.symlinks/flutter/darwin-x64-profile
path_provider: path_provider:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider/macos :path: Flutter/ephemeral/.symlinks/plugins/path_provider/macos
path_provider_macos: path_provider_macos:

View File

@ -21,7 +21,7 @@ packages:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.1" version: "2.4.2"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -56,7 +56,7 @@ packages:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.14.12" version: "1.14.13"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -143,14 +143,14 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "0.4.1" version: "0.6.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.6" version: "0.12.8"
meta: meta:
dependency: transitive dependency: transitive
description: description:
@ -171,7 +171,7 @@ packages:
name: path_provider name: path_provider
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.11" version: "1.6.14"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@ -192,7 +192,7 @@ packages:
name: path_provider_platform_interface name: path_provider_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.2" version: "1.0.3"
pedantic: pedantic:
dependency: transitive dependency: transitive
description: description:
@ -239,7 +239,7 @@ packages:
name: stack_trace name: stack_trace
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.9.3" version: "1.9.5"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
@ -267,14 +267,14 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.16" version: "0.2.17"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.6" version: "1.2.0"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -290,5 +290,5 @@ packages:
source: hosted source: hosted
version: "0.1.0" version: "0.1.0"
sdks: sdks:
dart: ">=2.7.0 <3.0.0" dart: ">=2.9.0-14.0.dev <3.0.0"
flutter: ">=1.12.13+hotfix.5 <2.0.0" flutter: ">=1.12.13+hotfix.5 <2.0.0"

View File

@ -34,7 +34,7 @@ flutter:
- assets/Logo/ - assets/Logo/
- assets/Images/ - assets/Images/
- assets/Images/WeAccept/ - assets/Images/WeAccept/
- assets/Weather/ - assets/weather/
- assets/example_with_images/ - assets/example_with_images/
- assets/example_with_images/images/ - assets/example_with_images/images/

View File

@ -33,6 +33,7 @@ void main() {
composition: composition, composition: composition,
controller: animation, controller: animation,
delegates: LottieDelegates(values: [delegate]), delegates: LottieDelegates(values: [delegate]),
addRepaintBoundary: false,
), ),
); );
await tester.pump(); await tester.pump();
@ -45,6 +46,7 @@ void main() {
composition: composition, composition: composition,
controller: animation, controller: animation,
delegates: LottieDelegates(values: []), delegates: LottieDelegates(values: []),
addRepaintBoundary: false,
), ),
); );
await tester.pump(); await tester.pump();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -42,7 +42,7 @@ class _CustomerPainter extends CustomPainter {
thumbSize; thumbSize;
drawable drawable
..setProgress(progress) ..setProgress(progress, frameRate: FrameRate.max)
..draw(canvas, rect); ..draw(canvas, rect);
++index; ++index;

View File

@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:lottie_example/main.dart'; import 'package:lottie_example/main_app.dart';
void main() { void main() {
testWidgets('Main sample', (tester) async { testWidgets('Main sample', (tester) async {

View File

@ -1,4 +1,5 @@
export 'src/composition.dart' show LottieComposition; export 'src/composition.dart' show LottieComposition;
export 'src/frame_rate.dart' show FrameRate;
export 'src/lottie.dart' show Lottie; export 'src/lottie.dart' show Lottie;
export 'src/lottie_builder.dart' show LottieBuilder; export 'src/lottie_builder.dart' show LottieBuilder;
export 'src/lottie_delegates.dart' show LottieDelegates; export 'src/lottie_delegates.dart' show LottieDelegates;

View File

@ -13,6 +13,7 @@ import '../../model/layer/base_layer.dart';
import '../../utils.dart'; import '../../utils.dart';
import '../../utils/dash_path.dart'; import '../../utils/dash_path.dart';
import '../../utils/misc.dart'; import '../../utils/misc.dart';
import '../../utils/path_factory.dart';
import '../../utils/utils.dart'; import '../../utils/utils.dart';
import '../../value/lottie_value_callback.dart'; import '../../value/lottie_value_callback.dart';
import '../keyframe/base_keyframe_animation.dart'; import '../keyframe/base_keyframe_animation.dart';
@ -25,8 +26,8 @@ import 'trim_path_content.dart';
abstract class BaseStrokeContent abstract class BaseStrokeContent
implements KeyPathElementContent, DrawingContent { implements KeyPathElementContent, DrawingContent {
final Path _path = Path(); final Path _path = PathFactory.create();
final Path _trimPathPath = Path(); final Path _trimPathPath = PathFactory.create();
final LottieDrawable lottieDrawable; final LottieDrawable lottieDrawable;
final BaseLayer layer; final BaseLayer layer;
final List<_PathGroup> _pathGroups = <_PathGroup>[]; final List<_PathGroup> _pathGroups = <_PathGroup>[];

View File

@ -9,6 +9,7 @@ import '../../model/key_path.dart';
import '../../model/key_path_element.dart'; import '../../model/key_path_element.dart';
import '../../model/layer/base_layer.dart'; import '../../model/layer/base_layer.dart';
import '../../utils.dart'; import '../../utils.dart';
import '../../utils/path_factory.dart';
import '../../value/lottie_value_callback.dart'; import '../../value/lottie_value_callback.dart';
import '../keyframe/transform_keyframe_animation.dart'; import '../keyframe/transform_keyframe_animation.dart';
import 'content.dart'; import 'content.dart';
@ -43,7 +44,7 @@ class ContentGroup implements DrawingContent, PathContent, KeyPathElement {
} }
final Matrix4 _matrix = Matrix4.identity(); final Matrix4 _matrix = Matrix4.identity();
final Path _path = Path(); final Path _path = PathFactory.create();
@override @override
final String name; final String name;

View File

@ -7,6 +7,7 @@ import '../../model/key_path.dart';
import '../../model/layer/base_layer.dart'; import '../../model/layer/base_layer.dart';
import '../../utils.dart'; import '../../utils.dart';
import '../../utils/misc.dart'; import '../../utils/misc.dart';
import '../../utils/path_factory.dart';
import '../../value/lottie_value_callback.dart'; import '../../value/lottie_value_callback.dart';
import '../keyframe/base_keyframe_animation.dart'; import '../keyframe/base_keyframe_animation.dart';
import 'compound_trim_path_content.dart'; import 'compound_trim_path_content.dart';
@ -18,7 +19,7 @@ import 'trim_path_content.dart';
class EllipseContent implements PathContent, KeyPathElementContent { class EllipseContent implements PathContent, KeyPathElementContent {
static final double _ellipseControlPointPercentage = 0.55228; static final double _ellipseControlPointPercentage = 0.55228;
final Path _path = Path(); final Path _path = PathFactory.create();
@override @override
final String name; final String name;

View File

@ -8,6 +8,7 @@ import '../../model/key_path.dart';
import '../../model/layer/base_layer.dart'; import '../../model/layer/base_layer.dart';
import '../../utils.dart'; import '../../utils.dart';
import '../../utils/misc.dart'; import '../../utils/misc.dart';
import '../../utils/path_factory.dart';
import '../../value/lottie_value_callback.dart'; import '../../value/lottie_value_callback.dart';
import '../keyframe/base_keyframe_animation.dart'; import '../keyframe/base_keyframe_animation.dart';
import '../keyframe/value_callback_keyframe_animation.dart'; import '../keyframe/value_callback_keyframe_animation.dart';
@ -17,7 +18,7 @@ import 'key_path_element_content.dart';
import 'path_content.dart'; import 'path_content.dart';
class FillContent implements DrawingContent, KeyPathElementContent { class FillContent implements DrawingContent, KeyPathElementContent {
final Path _path = Path(); final Path _path = PathFactory.create();
final Paint _paint = Paint(); final Paint _paint = Paint();
final BaseLayer layer; final BaseLayer layer;
@override @override
@ -70,6 +71,9 @@ class FillContent implements DrawingContent, KeyPathElementContent {
var alpha = var alpha =
((parentAlpha / 255.0 * _opacityAnimation.value / 100.0) * 255).round(); ((parentAlpha / 255.0 * _opacityAnimation.value / 100.0) * 255).round();
_paint.setAlpha(alpha.clamp(0, 255).toInt()); _paint.setAlpha(alpha.clamp(0, 255).toInt());
if (lottieDrawable.antiAliasingSuggested) {
_paint.isAntiAlias = true;
}
if (_colorFilterAnimation != null) { if (_colorFilterAnimation != null) {
_paint.colorFilter = _colorFilterAnimation.value; _paint.colorFilter = _colorFilterAnimation.value;
@ -77,11 +81,13 @@ class FillContent implements DrawingContent, KeyPathElementContent {
_path.reset(); _path.reset();
for (var i = 0; i < _paths.length; i++) { for (var i = 0; i < _paths.length; i++) {
_path.addPath(_paths[i].getPath(), Offset.zero, _path.addPath(_paths[i].getPath(), Offset.zero);
matrix4: parentMatrix.storage);
} }
canvas.save();
canvas.transform(parentMatrix.storage);
canvas.drawPath(_path, _paint); canvas.drawPath(_path, _paint);
canvas.restore();
L.endSection('FillContent#draw'); L.endSection('FillContent#draw');
} }

View File

@ -10,6 +10,7 @@ import '../../model/key_path.dart';
import '../../model/layer/base_layer.dart'; import '../../model/layer/base_layer.dart';
import '../../utils.dart'; import '../../utils.dart';
import '../../utils/misc.dart'; import '../../utils/misc.dart';
import '../../utils/path_factory.dart';
import '../../value/lottie_value_callback.dart'; import '../../value/lottie_value_callback.dart';
import '../keyframe/base_keyframe_animation.dart'; import '../keyframe/base_keyframe_animation.dart';
import '../keyframe/value_callback_keyframe_animation.dart'; import '../keyframe/value_callback_keyframe_animation.dart';
@ -25,7 +26,7 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
final GradientFill _fill; final GradientFill _fill;
final _linearGradientCache = <int, Gradient>{}; final _linearGradientCache = <int, Gradient>{};
final _radialGradientCache = <int, Gradient>{}; final _radialGradientCache = <int, Gradient>{};
final _path = Path(); final _path = PathFactory.create();
final _paint = Paint(); final _paint = Paint();
final _paths = <PathContent>[]; final _paths = <PathContent>[];
final BaseKeyframeAnimation<GradientColor, GradientColor> _colorAnimation; final BaseKeyframeAnimation<GradientColor, GradientColor> _colorAnimation;
@ -85,15 +86,14 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
L.beginSection('GradientFillContent#draw'); L.beginSection('GradientFillContent#draw');
_path.reset(); _path.reset();
for (var i = 0; i < _paths.length; i++) { for (var i = 0; i < _paths.length; i++) {
_path.addPath(_paths[i].getPath(), Offset.zero, _path.addPath(_paths[i].getPath(), Offset.zero);
matrix4: parentMatrix.storage);
} }
Gradient gradient; Gradient gradient;
if (_fill.gradientType == GradientType.linear) { if (_fill.gradientType == GradientType.linear) {
gradient = _getLinearGradient(parentMatrix); gradient = _getLinearGradient();
} else { } else {
gradient = _getRadialGradient(parentMatrix); gradient = _getRadialGradient();
} }
_paint.shader = gradient; _paint.shader = gradient;
@ -105,8 +105,14 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
var alpha = var alpha =
((parentAlpha / 255.0 * _opacityAnimation.value / 100.0) * 255).round(); ((parentAlpha / 255.0 * _opacityAnimation.value / 100.0) * 255).round();
_paint.setAlpha(alpha.clamp(0, 255).toInt()); _paint.setAlpha(alpha.clamp(0, 255).toInt());
if (lottieDrawable.antiAliasingSuggested) {
_paint.isAntiAlias = true;
}
canvas.save();
canvas.transform(parentMatrix.storage);
canvas.drawPath(_path, _paint); canvas.drawPath(_path, _paint);
canvas.restore();
L.endSection('GradientFillContent#draw'); L.endSection('GradientFillContent#draw');
} }
@ -124,8 +130,8 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
outBounds.right + 1, outBounds.bottom + 1); outBounds.right + 1, outBounds.bottom + 1);
} }
Gradient _getLinearGradient(Matrix4 parentMatrix) { Gradient _getLinearGradient() {
var gradientHash = _getGradientHash(parentMatrix); var gradientHash = _getGradientHash();
var gradient = _linearGradientCache[gradientHash]; var gradient = _linearGradientCache[gradientHash];
if (gradient != null) { if (gradient != null) {
return gradient; return gradient;
@ -135,14 +141,14 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
var gradientColor = _colorAnimation.value; var gradientColor = _colorAnimation.value;
var colors = _applyDynamicColorsIfNeeded(gradientColor.colors); var colors = _applyDynamicColorsIfNeeded(gradientColor.colors);
var positions = gradientColor.positions; var positions = gradientColor.positions;
gradient = Gradient.linear(startPoint, endPoint, colors, positions, gradient = Gradient.linear(
TileMode.clamp, parentMatrix.storage); startPoint, endPoint, colors, positions, TileMode.clamp);
_linearGradientCache[gradientHash] = gradient; _linearGradientCache[gradientHash] = gradient;
return gradient; return gradient;
} }
Gradient _getRadialGradient(Matrix4 parentMatrix) { Gradient _getRadialGradient() {
var gradientHash = _getGradientHash(parentMatrix); var gradientHash = _getGradientHash();
var gradient = _radialGradientCache[gradientHash]; var gradient = _radialGradientCache[gradientHash];
if (gradient != null) { if (gradient != null) {
return gradient; return gradient;
@ -160,13 +166,13 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
if (radius <= 0) { if (radius <= 0) {
radius = 0.001; radius = 0.001;
} }
gradient = Gradient.radial(startPoint, radius, colors, positions, gradient =
TileMode.clamp, parentMatrix.storage); Gradient.radial(startPoint, radius, colors, positions, TileMode.clamp);
_radialGradientCache[gradientHash] = gradient; _radialGradientCache[gradientHash] = gradient;
return gradient; return gradient;
} }
int _getGradientHash(Matrix4 parentMatrix) { int _getGradientHash() {
var startPointProgress = var startPointProgress =
(_startPointAnimation.progress * _cacheSteps).round(); (_startPointAnimation.progress * _cacheSteps).round();
var endPointProgress = (_endPointAnimation.progress * _cacheSteps).round(); var endPointProgress = (_endPointAnimation.progress * _cacheSteps).round();
@ -181,7 +187,6 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
if (colorProgress != 0) { if (colorProgress != 0) {
hash = hash * 31 * colorProgress; hash = hash * 31 * colorProgress;
} }
hash *= 31 * parentMatrix.hashCode;
return hash; return hash;
} }

View File

@ -1,15 +1,16 @@
import 'dart:ui'; import 'dart:ui';
import '../../model/content/merge_paths.dart'; import '../../model/content/merge_paths.dart';
import '../../utils.dart'; import '../../utils.dart';
import '../../utils/path_factory.dart';
import 'content.dart'; import 'content.dart';
import 'content_group.dart'; import 'content_group.dart';
import 'greedy_content.dart'; import 'greedy_content.dart';
import 'path_content.dart'; import 'path_content.dart';
class MergePathsContent implements PathContent, GreedyContent { class MergePathsContent implements PathContent, GreedyContent {
final Path _firstPath = Path(); final Path _firstPath = PathFactory.create();
final Path _remainderPath = Path(); final Path _remainderPath = PathFactory.create();
final Path _path = Path(); final Path _path = PathFactory.create();
final List<PathContent> _pathContents = <PathContent>[]; final List<PathContent> _pathContents = <PathContent>[];
final MergePaths _mergePaths; final MergePaths _mergePaths;

View File

@ -8,6 +8,7 @@ import '../../model/content/shape_trim_path.dart';
import '../../model/key_path.dart'; import '../../model/key_path.dart';
import '../../model/layer/base_layer.dart'; import '../../model/layer/base_layer.dart';
import '../../utils/misc.dart'; import '../../utils/misc.dart';
import '../../utils/path_factory.dart';
import '../../value/lottie_value_callback.dart'; import '../../value/lottie_value_callback.dart';
import '../keyframe/base_keyframe_animation.dart'; import '../keyframe/base_keyframe_animation.dart';
import 'compound_trim_path_content.dart'; import 'compound_trim_path_content.dart';
@ -23,7 +24,7 @@ class PolystarContent implements PathContent, KeyPathElementContent {
/// work otherwise. /// work otherwise.
static final _polystarMagicNumber = .47829; static final _polystarMagicNumber = .47829;
static final _polygonMagicNumber = .25; static final _polygonMagicNumber = .25;
final _path = Path(); final _path = PathFactory.create();
final LottieDrawable lottieDrawable; final LottieDrawable lottieDrawable;
final PolystarShape _polystarShape; final PolystarShape _polystarShape;

Some files were not shown because too many files have changed in this diff Show More