Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
548c77dc45 | |||
45a4c0b981 |
14
CHANGELOG.md
@ -1,3 +1,17 @@
|
|||||||
|
## [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]
|
||||||
|
- Remove direct dependencies on dart:io to support Flutter Web
|
||||||
|
|
||||||
## [0.5.0]
|
## [0.5.0]
|
||||||
- Support loading animation from network in a web app
|
- Support loading animation from network in a web app
|
||||||
- Fix a couple of bugs with the web dev compiler
|
- Fix a couple of bugs with the web dev compiler
|
||||||
|
@ -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`
|
||||||
|
@ -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'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
@ -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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -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:
|
||||||
|
@ -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:
|
||||||
@ -35,7 +35,7 @@ packages:
|
|||||||
name: characters
|
name: characters
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.1.0-nullsafety"
|
||||||
charcode:
|
charcode:
|
||||||
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.15.0-nullsafety"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -143,21 +143,21 @@ 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:
|
||||||
name: meta
|
name: meta
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.8"
|
version: "1.3.0-nullsafety"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -199,7 +199,7 @@ packages:
|
|||||||
name: pedantic
|
name: pedantic
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.0"
|
version: "1.9.2"
|
||||||
platform:
|
platform:
|
||||||
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,21 +267,21 @@ 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.3.0-nullsafety"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.8"
|
version: "2.1.0-nullsafety"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
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-18.0 <2.9.0"
|
||||||
flutter: ">=1.12.13+hotfix.5 <2.0.0"
|
flutter: ">=1.12.13+hotfix.5 <2.0.0"
|
||||||
|
@ -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();
|
||||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 20 KiB |
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -3,6 +3,7 @@ import 'dart:typed_data';
|
|||||||
import 'package:archive/archive.dart';
|
import 'package:archive/archive.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'frame_rate.dart';
|
||||||
import 'logger.dart';
|
import 'logger.dart';
|
||||||
import 'lottie_image_asset.dart';
|
import 'lottie_image_asset.dart';
|
||||||
import 'model/font.dart';
|
import 'model/font.dart';
|
||||||
@ -133,9 +134,11 @@ class LottieComposition {
|
|||||||
Rectangle<int> get bounds => _bounds;
|
Rectangle<int> get bounds => _bounds;
|
||||||
|
|
||||||
Duration get duration {
|
Duration get duration {
|
||||||
return Duration(milliseconds: (durationFrames / _frameRate * 1000).round());
|
return Duration(milliseconds: (seconds * 1000).round());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double get seconds => durationFrames / _frameRate;
|
||||||
|
|
||||||
double get startFrame => _startFrame;
|
double get startFrame => _startFrame;
|
||||||
|
|
||||||
double get endFrame => _endFrame;
|
double get endFrame => _endFrame;
|
||||||
@ -176,6 +179,24 @@ class LottieComposition {
|
|||||||
return _endFrame - _startFrame;
|
return _endFrame - _startFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a "rounded" progress value according to the frameRate
|
||||||
|
double roundProgress(double progress, {@required FrameRate frameRate}) {
|
||||||
|
num fps;
|
||||||
|
if (frameRate == FrameRate.max) {
|
||||||
|
return progress;
|
||||||
|
} else if (frameRate == FrameRate.composition) {
|
||||||
|
fps = this.frameRate;
|
||||||
|
}
|
||||||
|
fps ??= frameRate.framesPerSecond;
|
||||||
|
|
||||||
|
var totalFrameCount = seconds * fps;
|
||||||
|
var frameIndex = (totalFrameCount * progress).toInt();
|
||||||
|
var roundedProgress = frameIndex / totalFrameCount;
|
||||||
|
assert(roundedProgress >= 0 && roundedProgress <= 1,
|
||||||
|
'Progress is $roundedProgress');
|
||||||
|
return roundedProgress;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
final sb = StringBuffer('LottieComposition:\n');
|
final sb = StringBuffer('LottieComposition:\n');
|
||||||
|
9
lib/src/frame_rate.dart
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
class FrameRate {
|
||||||
|
static final max = FrameRate._special(0);
|
||||||
|
static final composition = FrameRate._special(-1);
|
||||||
|
|
||||||
|
final double framesPerSecond;
|
||||||
|
|
||||||
|
FrameRate(this.framesPerSecond) : assert(framesPerSecond > 0);
|
||||||
|
FrameRate._special(this.framesPerSecond);
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
import 'dart:io';
|
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import '../lottie.dart';
|
import '../lottie.dart';
|
||||||
|
import 'frame_rate.dart';
|
||||||
import 'l.dart';
|
import 'l.dart';
|
||||||
import 'lottie_builder.dart';
|
import 'lottie_builder.dart';
|
||||||
import 'options.dart';
|
import 'options.dart';
|
||||||
@ -23,36 +23,44 @@ class Lottie extends StatefulWidget {
|
|||||||
this.alignment,
|
this.alignment,
|
||||||
this.fit,
|
this.fit,
|
||||||
bool animate,
|
bool animate,
|
||||||
|
this.frameRate,
|
||||||
bool repeat,
|
bool repeat,
|
||||||
bool reverse,
|
bool reverse,
|
||||||
this.delegates,
|
this.delegates,
|
||||||
this.options,
|
this.options,
|
||||||
|
bool addRepaintBoundary,
|
||||||
}) : animate = animate ?? true,
|
}) : animate = animate ?? true,
|
||||||
reverse = reverse ?? false,
|
reverse = reverse ?? false,
|
||||||
repeat = repeat ?? true,
|
repeat = repeat ?? true,
|
||||||
|
addRepaintBoundary = addRepaintBoundary ?? true,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// Creates a widget that displays an [LottieComposition] obtained from an [AssetBundle].
|
/// Creates a widget that displays an [LottieComposition] obtained from an [AssetBundle].
|
||||||
static LottieBuilder asset(String name,
|
static LottieBuilder asset(
|
||||||
{Animation<double> controller,
|
String name, {
|
||||||
bool animate,
|
Animation<double> controller,
|
||||||
bool repeat,
|
bool animate,
|
||||||
bool reverse,
|
FrameRate frameRate,
|
||||||
LottieDelegates delegates,
|
bool repeat,
|
||||||
LottieOptions options,
|
bool reverse,
|
||||||
void Function(LottieComposition) onLoaded,
|
LottieDelegates delegates,
|
||||||
LottieImageProviderFactory imageProviderFactory,
|
LottieOptions options,
|
||||||
Key key,
|
void Function(LottieComposition) onLoaded,
|
||||||
AssetBundle bundle,
|
LottieImageProviderFactory imageProviderFactory,
|
||||||
LottieFrameBuilder frameBuilder,
|
Key key,
|
||||||
double width,
|
AssetBundle bundle,
|
||||||
double height,
|
LottieFrameBuilder frameBuilder,
|
||||||
BoxFit fit,
|
double width,
|
||||||
Alignment alignment,
|
double height,
|
||||||
String package}) =>
|
BoxFit fit,
|
||||||
|
Alignment alignment,
|
||||||
|
String package,
|
||||||
|
bool addRepaintBoundary,
|
||||||
|
}) =>
|
||||||
LottieBuilder.asset(
|
LottieBuilder.asset(
|
||||||
name,
|
name,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
frameRate: frameRate,
|
||||||
animate: animate,
|
animate: animate,
|
||||||
repeat: repeat,
|
repeat: repeat,
|
||||||
reverse: reverse,
|
reverse: reverse,
|
||||||
@ -68,12 +76,14 @@ class Lottie extends StatefulWidget {
|
|||||||
fit: fit,
|
fit: fit,
|
||||||
alignment: alignment,
|
alignment: alignment,
|
||||||
package: package,
|
package: package,
|
||||||
|
addRepaintBoundary: addRepaintBoundary,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Creates a widget that displays an [LottieComposition] obtained from a [File].
|
/// Creates a widget that displays an [LottieComposition] obtained from a [File].
|
||||||
static LottieBuilder file(
|
static LottieBuilder file(
|
||||||
File file, {
|
Object /*io.File|html.File*/ file, {
|
||||||
Animation<double> controller,
|
Animation<double> controller,
|
||||||
|
FrameRate frameRate,
|
||||||
bool animate,
|
bool animate,
|
||||||
bool repeat,
|
bool repeat,
|
||||||
bool reverse,
|
bool reverse,
|
||||||
@ -87,10 +97,12 @@ class Lottie extends StatefulWidget {
|
|||||||
double height,
|
double height,
|
||||||
BoxFit fit,
|
BoxFit fit,
|
||||||
Alignment alignment,
|
Alignment alignment,
|
||||||
|
bool addRepaintBoundary,
|
||||||
}) =>
|
}) =>
|
||||||
LottieBuilder.file(
|
LottieBuilder.file(
|
||||||
file,
|
file,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
frameRate: frameRate,
|
||||||
animate: animate,
|
animate: animate,
|
||||||
repeat: repeat,
|
repeat: repeat,
|
||||||
reverse: reverse,
|
reverse: reverse,
|
||||||
@ -104,12 +116,14 @@ class Lottie extends StatefulWidget {
|
|||||||
height: height,
|
height: height,
|
||||||
fit: fit,
|
fit: fit,
|
||||||
alignment: alignment,
|
alignment: alignment,
|
||||||
|
addRepaintBoundary: addRepaintBoundary,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Creates a widget that displays an [LottieComposition] obtained from a [Uint8List].
|
/// Creates a widget that displays an [LottieComposition] obtained from a [Uint8List].
|
||||||
static LottieBuilder memory(
|
static LottieBuilder memory(
|
||||||
Uint8List bytes, {
|
Uint8List bytes, {
|
||||||
Animation<double> controller,
|
Animation<double> controller,
|
||||||
|
FrameRate frameRate,
|
||||||
bool animate,
|
bool animate,
|
||||||
bool repeat,
|
bool repeat,
|
||||||
bool reverse,
|
bool reverse,
|
||||||
@ -123,10 +137,12 @@ class Lottie extends StatefulWidget {
|
|||||||
double height,
|
double height,
|
||||||
BoxFit fit,
|
BoxFit fit,
|
||||||
Alignment alignment,
|
Alignment alignment,
|
||||||
|
bool addRepaintBoundary,
|
||||||
}) =>
|
}) =>
|
||||||
LottieBuilder.memory(
|
LottieBuilder.memory(
|
||||||
bytes,
|
bytes,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
frameRate: frameRate,
|
||||||
animate: animate,
|
animate: animate,
|
||||||
repeat: repeat,
|
repeat: repeat,
|
||||||
reverse: reverse,
|
reverse: reverse,
|
||||||
@ -140,12 +156,14 @@ class Lottie extends StatefulWidget {
|
|||||||
height: height,
|
height: height,
|
||||||
fit: fit,
|
fit: fit,
|
||||||
alignment: alignment,
|
alignment: alignment,
|
||||||
|
addRepaintBoundary: addRepaintBoundary,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Creates a widget that displays an [LottieComposition] obtained from the network.
|
/// Creates a widget that displays an [LottieComposition] obtained from the network.
|
||||||
static LottieBuilder network(
|
static LottieBuilder network(
|
||||||
String url, {
|
String url, {
|
||||||
Animation<double> controller,
|
Animation<double> controller,
|
||||||
|
FrameRate frameRate,
|
||||||
bool animate,
|
bool animate,
|
||||||
bool repeat,
|
bool repeat,
|
||||||
bool reverse,
|
bool reverse,
|
||||||
@ -159,10 +177,12 @@ class Lottie extends StatefulWidget {
|
|||||||
double height,
|
double height,
|
||||||
BoxFit fit,
|
BoxFit fit,
|
||||||
Alignment alignment,
|
Alignment alignment,
|
||||||
|
bool addRepaintBoundary,
|
||||||
}) =>
|
}) =>
|
||||||
LottieBuilder.network(
|
LottieBuilder.network(
|
||||||
url,
|
url,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
frameRate: frameRate,
|
||||||
animate: animate,
|
animate: animate,
|
||||||
repeat: repeat,
|
repeat: repeat,
|
||||||
reverse: reverse,
|
reverse: reverse,
|
||||||
@ -176,6 +196,7 @@ class Lottie extends StatefulWidget {
|
|||||||
height: height,
|
height: height,
|
||||||
fit: fit,
|
fit: fit,
|
||||||
alignment: alignment,
|
alignment: alignment,
|
||||||
|
addRepaintBoundary: addRepaintBoundary,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// The Lottie composition to animate.
|
/// The Lottie composition to animate.
|
||||||
@ -187,6 +208,14 @@ class Lottie extends StatefulWidget {
|
|||||||
/// with the properties [animate], [reverse]
|
/// with the properties [animate], [reverse]
|
||||||
final Animation<double> controller;
|
final Animation<double> controller;
|
||||||
|
|
||||||
|
/// The number of frames per second to render.
|
||||||
|
/// Use `FrameRate.composition` to use the original frame rate of the Lottie composition (default)
|
||||||
|
/// Use `FrameRate.max` to advance the animation progression at every frame.
|
||||||
|
///
|
||||||
|
/// The advantage of using a low frame rate is to preserve the device battery
|
||||||
|
/// by doing less rendering work.
|
||||||
|
final FrameRate frameRate;
|
||||||
|
|
||||||
/// If no controller is specified, this value indicate whether or not the
|
/// If no controller is specified, this value indicate whether or not the
|
||||||
/// Lottie animation should be played automatically (default to true).
|
/// Lottie animation should be played automatically (default to true).
|
||||||
/// If there is an animation controller specified, this property has no effect.
|
/// If there is an animation controller specified, this property has no effect.
|
||||||
@ -250,6 +279,13 @@ class Lottie extends StatefulWidget {
|
|||||||
/// - enableMergePaths: Enable merge path support
|
/// - enableMergePaths: Enable merge path support
|
||||||
final LottieOptions options;
|
final LottieOptions options;
|
||||||
|
|
||||||
|
/// Indicate to automatically add a `RepaintBoundary` widget around the animation.
|
||||||
|
/// This allows to optimize the app performance by isolating the animation in its
|
||||||
|
/// own `Layer`.
|
||||||
|
///
|
||||||
|
/// This property is `true` by default.
|
||||||
|
final bool addRepaintBoundary;
|
||||||
|
|
||||||
static bool get traceEnabled => L.traceEnabled;
|
static bool get traceEnabled => L.traceEnabled;
|
||||||
static set traceEnabled(bool enabled) {
|
static set traceEnabled(bool enabled) {
|
||||||
L.traceEnabled = enabled;
|
L.traceEnabled = enabled;
|
||||||
@ -304,18 +340,27 @@ class _LottieState extends State<Lottie> with TickerProviderStateMixin {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedBuilder(
|
Widget child = AnimatedBuilder(
|
||||||
animation: _progressAnimation,
|
animation: _progressAnimation,
|
||||||
builder: (context, _) => RawLottie(
|
builder: (context, _) {
|
||||||
composition: widget.composition,
|
return RawLottie(
|
||||||
delegates: widget.delegates,
|
composition: widget.composition,
|
||||||
options: widget.options,
|
delegates: widget.delegates,
|
||||||
progress: _progressAnimation.value,
|
options: widget.options,
|
||||||
width: widget.width,
|
progress: _progressAnimation.value,
|
||||||
height: widget.height,
|
frameRate: widget.frameRate,
|
||||||
fit: widget.fit,
|
width: widget.width,
|
||||||
alignment: widget.alignment,
|
height: widget.height,
|
||||||
),
|
fit: widget.fit,
|
||||||
|
alignment: widget.alignment,
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (widget.addRepaintBoundary) {
|
||||||
|
child = RepaintBoundary(child: child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import '../lottie.dart';
|
import '../lottie.dart';
|
||||||
|
import 'frame_rate.dart';
|
||||||
import 'lottie.dart';
|
import 'lottie.dart';
|
||||||
import 'providers/asset_provider.dart';
|
import 'providers/asset_provider.dart';
|
||||||
import 'providers/file_provider.dart';
|
import 'providers/file_provider.dart';
|
||||||
@ -36,6 +36,7 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
Key key,
|
Key key,
|
||||||
@required this.lottie,
|
@required this.lottie,
|
||||||
this.controller,
|
this.controller,
|
||||||
|
this.frameRate,
|
||||||
this.animate,
|
this.animate,
|
||||||
this.reverse,
|
this.reverse,
|
||||||
this.repeat,
|
this.repeat,
|
||||||
@ -47,6 +48,7 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
this.height,
|
this.height,
|
||||||
this.fit,
|
this.fit,
|
||||||
this.alignment,
|
this.alignment,
|
||||||
|
this.addRepaintBoundary,
|
||||||
}) : assert(lottie != null),
|
}) : assert(lottie != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@ -55,6 +57,7 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
String src, {
|
String src, {
|
||||||
Map<String, String> headers,
|
Map<String, String> headers,
|
||||||
this.controller,
|
this.controller,
|
||||||
|
this.frameRate,
|
||||||
this.animate,
|
this.animate,
|
||||||
this.reverse,
|
this.reverse,
|
||||||
this.repeat,
|
this.repeat,
|
||||||
@ -68,6 +71,7 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
this.height,
|
this.height,
|
||||||
this.fit,
|
this.fit,
|
||||||
this.alignment,
|
this.alignment,
|
||||||
|
this.addRepaintBoundary,
|
||||||
}) : lottie = NetworkLottie(src,
|
}) : lottie = NetworkLottie(src,
|
||||||
headers: headers, imageProviderFactory: imageProviderFactory),
|
headers: headers, imageProviderFactory: imageProviderFactory),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
@ -83,8 +87,9 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
/// `android.permission.READ_EXTERNAL_STORAGE` permission.
|
/// `android.permission.READ_EXTERNAL_STORAGE` permission.
|
||||||
///
|
///
|
||||||
LottieBuilder.file(
|
LottieBuilder.file(
|
||||||
File file, {
|
Object /*io.File|html.File*/ file, {
|
||||||
this.controller,
|
this.controller,
|
||||||
|
this.frameRate,
|
||||||
this.animate,
|
this.animate,
|
||||||
this.reverse,
|
this.reverse,
|
||||||
this.repeat,
|
this.repeat,
|
||||||
@ -98,6 +103,7 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
this.height,
|
this.height,
|
||||||
this.fit,
|
this.fit,
|
||||||
this.alignment,
|
this.alignment,
|
||||||
|
this.addRepaintBoundary,
|
||||||
}) : lottie = FileLottie(file, imageProviderFactory: imageProviderFactory),
|
}) : lottie = FileLottie(file, imageProviderFactory: imageProviderFactory),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@ -105,6 +111,7 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
LottieBuilder.asset(
|
LottieBuilder.asset(
|
||||||
String name, {
|
String name, {
|
||||||
this.controller,
|
this.controller,
|
||||||
|
this.frameRate,
|
||||||
this.animate,
|
this.animate,
|
||||||
this.reverse,
|
this.reverse,
|
||||||
this.repeat,
|
this.repeat,
|
||||||
@ -120,6 +127,7 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
this.fit,
|
this.fit,
|
||||||
this.alignment,
|
this.alignment,
|
||||||
String package,
|
String package,
|
||||||
|
this.addRepaintBoundary,
|
||||||
}) : lottie = AssetLottie(name,
|
}) : lottie = AssetLottie(name,
|
||||||
bundle: bundle,
|
bundle: bundle,
|
||||||
package: package,
|
package: package,
|
||||||
@ -130,6 +138,7 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
LottieBuilder.memory(
|
LottieBuilder.memory(
|
||||||
Uint8List bytes, {
|
Uint8List bytes, {
|
||||||
this.controller,
|
this.controller,
|
||||||
|
this.frameRate,
|
||||||
this.animate,
|
this.animate,
|
||||||
this.reverse,
|
this.reverse,
|
||||||
this.repeat,
|
this.repeat,
|
||||||
@ -143,6 +152,7 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
this.height,
|
this.height,
|
||||||
this.fit,
|
this.fit,
|
||||||
this.alignment,
|
this.alignment,
|
||||||
|
this.addRepaintBoundary,
|
||||||
}) : lottie =
|
}) : lottie =
|
||||||
MemoryLottie(bytes, imageProviderFactory: imageProviderFactory),
|
MemoryLottie(bytes, imageProviderFactory: imageProviderFactory),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
@ -161,6 +171,11 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
/// Lottie animation.
|
/// Lottie animation.
|
||||||
final Animation<double> controller;
|
final Animation<double> controller;
|
||||||
|
|
||||||
|
/// The number of frames per second to render.
|
||||||
|
/// Use `FrameRate.composition` to use the original frame rate of the Lottie composition (default)
|
||||||
|
/// Use `FrameRate.max` to advance the animation progression at every frame.
|
||||||
|
final FrameRate frameRate;
|
||||||
|
|
||||||
/// If no controller is specified, this value indicate whether or not the
|
/// If no controller is specified, this value indicate whether or not the
|
||||||
/// Lottie animation should be played automatically (default to true).
|
/// Lottie animation should be played automatically (default to true).
|
||||||
/// If there is an animation controller specified, this property has no effect.
|
/// If there is an animation controller specified, this property has no effect.
|
||||||
@ -321,6 +336,13 @@ class LottieBuilder extends StatefulWidget {
|
|||||||
/// relative to text direction.
|
/// relative to text direction.
|
||||||
final AlignmentGeometry alignment;
|
final AlignmentGeometry alignment;
|
||||||
|
|
||||||
|
/// Indicate to automatically add a `RepaintBoundary` widget around the animation.
|
||||||
|
/// This allows to optimize the app performance by isolating the animation in its
|
||||||
|
/// own `Layer`.
|
||||||
|
///
|
||||||
|
/// This property is `true` by default.
|
||||||
|
final bool addRepaintBoundary;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_LottieBuilderState createState() => _LottieBuilderState();
|
_LottieBuilderState createState() => _LottieBuilderState();
|
||||||
|
|
||||||
@ -384,6 +406,7 @@ class _LottieBuilderState extends State<LottieBuilder> {
|
|||||||
Widget result = Lottie(
|
Widget result = Lottie(
|
||||||
composition: composition,
|
composition: composition,
|
||||||
controller: widget.controller,
|
controller: widget.controller,
|
||||||
|
frameRate: widget.frameRate,
|
||||||
animate: widget.animate,
|
animate: widget.animate,
|
||||||
reverse: widget.reverse,
|
reverse: widget.reverse,
|
||||||
repeat: widget.repeat,
|
repeat: widget.repeat,
|
||||||
@ -393,6 +416,7 @@ class _LottieBuilderState extends State<LottieBuilder> {
|
|||||||
height: widget.height,
|
height: widget.height,
|
||||||
fit: widget.fit,
|
fit: widget.fit,
|
||||||
alignment: widget.alignment,
|
alignment: widget.alignment,
|
||||||
|
addRepaintBoundary: widget.addRepaintBoundary,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (widget.frameBuilder != null) {
|
if (widget.frameBuilder != null) {
|
||||||
|
@ -3,7 +3,7 @@ import 'lottie_drawable.dart';
|
|||||||
import 'value_delegate.dart';
|
import 'value_delegate.dart';
|
||||||
|
|
||||||
// TODO(xha): recognize style Bold, Medium, Regular, SemiBold, etc...
|
// TODO(xha): recognize style Bold, Medium, Regular, SemiBold, etc...
|
||||||
TextStyle _defaultTextStyleDelegate(LottieFontStyle font) =>
|
TextStyle defaultTextStyleDelegate(LottieFontStyle font) =>
|
||||||
TextStyle(fontFamily: font.fontFamily);
|
TextStyle(fontFamily: font.fontFamily);
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
@ -49,7 +49,7 @@ class LottieDelegates {
|
|||||||
this.text,
|
this.text,
|
||||||
TextStyle Function(LottieFontStyle) textStyle,
|
TextStyle Function(LottieFontStyle) textStyle,
|
||||||
this.values,
|
this.values,
|
||||||
}) : textStyle = textStyle ?? _defaultTextStyleDelegate;
|
}) : textStyle = textStyle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
|
@ -2,6 +2,7 @@ import 'dart:ui' as ui;
|
|||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
import 'composition.dart';
|
import 'composition.dart';
|
||||||
|
import 'frame_rate.dart';
|
||||||
import 'lottie_delegates.dart';
|
import 'lottie_delegates.dart';
|
||||||
import 'model/key_path.dart';
|
import 'model/key_path.dart';
|
||||||
import 'model/layer/composition_layer.dart';
|
import 'model/layer/composition_layer.dart';
|
||||||
@ -43,26 +44,32 @@ class LottieDrawable {
|
|||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double get progress => _progress;
|
double get progress => _progress ?? 0.0;
|
||||||
double _progress = 0.0;
|
double _progress;
|
||||||
bool setProgress(double value) {
|
bool setProgress(double value, {FrameRate frameRate}) {
|
||||||
_isDirty = false;
|
frameRate ??= FrameRate.composition;
|
||||||
_progress = value;
|
var roundedProgress =
|
||||||
_compositionLayer.setProgress(value);
|
composition.roundProgress(value, frameRate: frameRate);
|
||||||
return _isDirty;
|
if (roundedProgress != _progress) {
|
||||||
|
_isDirty = false;
|
||||||
|
_progress = roundedProgress;
|
||||||
|
_compositionLayer.setProgress(roundedProgress);
|
||||||
|
return _isDirty;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LottieDelegates get delegates => _delegates;
|
LottieDelegates get delegates => _delegates;
|
||||||
set delegates(LottieDelegates delegates) {
|
set delegates(LottieDelegates delegates) {
|
||||||
delegates ??= LottieDelegates();
|
|
||||||
if (_delegates != delegates) {
|
if (_delegates != delegates) {
|
||||||
_delegates = delegates;
|
_delegates = delegates;
|
||||||
_updateValueDelegates(delegates.values);
|
_updateValueDelegates(delegates?.values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get useTextGlyphs {
|
bool get useTextGlyphs {
|
||||||
return delegates.text == null && composition.characters.isNotEmpty;
|
return delegates?.text == null && composition.characters.isNotEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Image getImageAsset(String ref) {
|
ui.Image getImageAsset(String ref) {
|
||||||
@ -75,8 +82,8 @@ class LottieDrawable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TextStyle getTextStyle(String font, String style) {
|
TextStyle getTextStyle(String font, String style) {
|
||||||
return _delegates
|
return (_delegates?.textStyle ?? defaultTextStyleDelegate)(
|
||||||
.textStyle(LottieFontStyle(fontFamily: font, style: style));
|
LottieFontStyle(fontFamily: font, style: style));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ValueDelegate> _valueDelegates = <ValueDelegate>[];
|
List<ValueDelegate> _valueDelegates = <ValueDelegate>[];
|
||||||
|
@ -232,7 +232,7 @@ class TextLayer extends BaseLayer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var text = documentData.text;
|
var text = documentData.text;
|
||||||
var textDelegate = lottieDrawable.delegates.text;
|
var textDelegate = lottieDrawable.delegates?.text;
|
||||||
if (textDelegate != null) {
|
if (textDelegate != null) {
|
||||||
text = textDelegate(text);
|
text = textDelegate(text);
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
import 'dart:io';
|
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import '../composition.dart';
|
import '../composition.dart';
|
||||||
import '../lottie_image_asset.dart';
|
import '../lottie_image_asset.dart';
|
||||||
import 'load_image.dart';
|
import 'load_image.dart';
|
||||||
import 'lottie_provider.dart';
|
import 'lottie_provider.dart';
|
||||||
|
import 'provider_io.dart' if (dart.library.html) 'provider_web.dart' as io;
|
||||||
|
|
||||||
class FileLottie extends LottieProvider {
|
class FileLottie extends LottieProvider {
|
||||||
FileLottie(this.file, {LottieImageProviderFactory imageProviderFactory})
|
FileLottie(this.file, {LottieImageProviderFactory imageProviderFactory})
|
||||||
: super(imageProviderFactory: imageProviderFactory);
|
: super(imageProviderFactory: imageProviderFactory);
|
||||||
|
|
||||||
final File file;
|
final Object /*io.File|html.File*/ file;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LottieComposition> load() async {
|
Future<LottieComposition> load() async {
|
||||||
var cacheKey = 'file-${file.path}';
|
var cacheKey = 'file-${io.filePath(file)}';
|
||||||
return sharedLottieCache.putIfAbsent(cacheKey, () async {
|
return sharedLottieCache.putIfAbsent(cacheKey, () async {
|
||||||
var bytes = await file.readAsBytes();
|
var bytes = await io.loadFile(file);
|
||||||
var composition = await LottieComposition.fromBytes(bytes,
|
var composition = await LottieComposition.fromBytes(bytes,
|
||||||
name: p.basenameWithoutExtension(file.path));
|
name: p.basenameWithoutExtension(io.filePath(file)));
|
||||||
|
|
||||||
for (var image in composition.images.values) {
|
for (var image in composition.images.values) {
|
||||||
image.loadedImage ??= await _loadImage(composition, image);
|
image.loadedImage ??= await _loadImage(composition, image);
|
||||||
@ -33,11 +32,7 @@ class FileLottie extends LottieProvider {
|
|||||||
LottieComposition composition, LottieImageAsset lottieImage) {
|
LottieComposition composition, LottieImageAsset lottieImage) {
|
||||||
var imageProvider = getImageProvider(lottieImage);
|
var imageProvider = getImageProvider(lottieImage);
|
||||||
|
|
||||||
if (imageProvider == null) {
|
imageProvider ??= io.loadImageForFile(file, lottieImage);
|
||||||
var imagePath = p.url.join(
|
|
||||||
p.dirname(file.path), lottieImage.dirName, lottieImage.fileName);
|
|
||||||
imageProvider = FileImage(File(imagePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
return loadImage(composition, lottieImage, imageProvider);
|
return loadImage(composition, lottieImage, imageProvider);
|
||||||
}
|
}
|
||||||
@ -52,5 +47,5 @@ class FileLottie extends LottieProvider {
|
|||||||
int get hashCode => file.hashCode;
|
int get hashCode => file.hashCode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => '$runtimeType(file: ${file.path})';
|
String toString() => '$runtimeType(file: ${io.filePath(file)})';
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,7 @@ import '../composition.dart';
|
|||||||
import '../lottie_image_asset.dart';
|
import '../lottie_image_asset.dart';
|
||||||
import 'load_image.dart';
|
import 'load_image.dart';
|
||||||
import 'lottie_provider.dart';
|
import 'lottie_provider.dart';
|
||||||
import 'network_provider_io.dart'
|
import 'provider_io.dart' if (dart.library.html) 'provider_web.dart' as network;
|
||||||
if (dart.library.html) 'network_provider_web.dart' as network;
|
|
||||||
|
|
||||||
class NetworkLottie extends LottieProvider {
|
class NetworkLottie extends LottieProvider {
|
||||||
NetworkLottie(this.url,
|
NetworkLottie(this.url,
|
||||||
@ -22,7 +21,7 @@ class NetworkLottie extends LottieProvider {
|
|||||||
var cacheKey = 'network-$url';
|
var cacheKey = 'network-$url';
|
||||||
return sharedLottieCache.putIfAbsent(cacheKey, () async {
|
return sharedLottieCache.putIfAbsent(cacheKey, () async {
|
||||||
var resolved = Uri.base.resolve(url);
|
var resolved = Uri.base.resolve(url);
|
||||||
var bytes = await network.load(resolved, headers: headers);
|
var bytes = await network.loadHttp(resolved, headers: headers);
|
||||||
|
|
||||||
var composition = await LottieComposition.fromBytes(bytes,
|
var composition = await LottieComposition.fromBytes(bytes,
|
||||||
name: p.url.basenameWithoutExtension(url));
|
name: p.url.basenameWithoutExtension(url));
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import 'dart:html';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
Future<Uint8List> load(Uri uri, {Map<String, String> headers}) async {
|
|
||||||
var request = await HttpRequest.request(uri.toString(),
|
|
||||||
requestHeaders: headers, responseType: 'blob');
|
|
||||||
|
|
||||||
var reader = FileReader();
|
|
||||||
reader.readAsArrayBuffer(request.response as Blob);
|
|
||||||
await reader.onLoadEnd.first;
|
|
||||||
if (reader.readyState != FileReader.DONE) {
|
|
||||||
throw Exception('Error while reading $uri');
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader.result as Uint8List;
|
|
||||||
}
|
|
@ -1,10 +1,13 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import '../lottie_image_asset.dart';
|
||||||
|
|
||||||
final HttpClient _sharedHttpClient = HttpClient()..autoUncompress = false;
|
final HttpClient _sharedHttpClient = HttpClient()..autoUncompress = false;
|
||||||
|
|
||||||
Future<Uint8List> load(Uri uri, {Map<String, String> headers}) async {
|
Future<Uint8List> loadHttp(Uri uri, {Map<String, String> headers}) async {
|
||||||
var request = await _sharedHttpClient.getUrl(uri);
|
var request = await _sharedHttpClient.getUrl(uri);
|
||||||
headers?.forEach((String name, String value) {
|
headers?.forEach((String name, String value) {
|
||||||
request.headers.add(name, value);
|
request.headers.add(name, value);
|
||||||
@ -21,3 +24,19 @@ Future<Uint8List> load(Uri uri, {Map<String, String> headers}) async {
|
|||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Uint8List> loadFile(Object file) {
|
||||||
|
return (file as File).readAsBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
String filePath(Object file) {
|
||||||
|
return (file as File).path;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageProvider loadImageForFile(Object file, LottieImageAsset lottieImage) {
|
||||||
|
var fileIo = file as File;
|
||||||
|
|
||||||
|
var imagePath = p.url
|
||||||
|
.join(p.dirname(fileIo.path), lottieImage.dirName, lottieImage.fileName);
|
||||||
|
return FileImage(File(imagePath));
|
||||||
|
}
|
35
lib/src/providers/provider_web.dart
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import 'dart:html';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import '../lottie_image_asset.dart';
|
||||||
|
|
||||||
|
Future<Uint8List> loadHttp(Uri uri, {Map<String, String> headers}) async {
|
||||||
|
var request = await HttpRequest.request(uri.toString(),
|
||||||
|
requestHeaders: headers, responseType: 'blob');
|
||||||
|
|
||||||
|
return _loadBlob(request.response as Blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Uint8List> loadFile(Object file) {
|
||||||
|
return _loadBlob(file as File);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Uint8List> _loadBlob(Blob file) async {
|
||||||
|
var reader = FileReader();
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
|
||||||
|
await reader.onLoadEnd.first;
|
||||||
|
if (reader.readyState != FileReader.DONE) {
|
||||||
|
throw Exception('Error while reading blob');
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader.result as Uint8List;
|
||||||
|
}
|
||||||
|
|
||||||
|
String filePath(Object file) {
|
||||||
|
return (file as File).relativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageProvider loadImageForFile(Object file, LottieImageAsset lottieImage) {
|
||||||
|
return null;
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import '../lottie.dart';
|
import '../lottie.dart';
|
||||||
|
import 'frame_rate.dart';
|
||||||
import 'lottie_drawable.dart';
|
import 'lottie_drawable.dart';
|
||||||
import 'render_lottie.dart';
|
import 'render_lottie.dart';
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ class RawLottie extends LeafRenderObjectWidget {
|
|||||||
this.delegates,
|
this.delegates,
|
||||||
this.options,
|
this.options,
|
||||||
double progress,
|
double progress,
|
||||||
|
this.frameRate,
|
||||||
this.width,
|
this.width,
|
||||||
this.height,
|
this.height,
|
||||||
this.fit,
|
this.fit,
|
||||||
@ -34,6 +36,11 @@ class RawLottie extends LeafRenderObjectWidget {
|
|||||||
/// The progress of the Lottie animation (between 0.0 and 1.0).
|
/// The progress of the Lottie animation (between 0.0 and 1.0).
|
||||||
final double progress;
|
final double progress;
|
||||||
|
|
||||||
|
/// The number of frames per second to render.
|
||||||
|
/// Use `FrameRate.composition` to use the original frame rate of the Lottie composition (default)
|
||||||
|
/// Use `FrameRate.max` to advance the animation progression at every frame.
|
||||||
|
final FrameRate frameRate;
|
||||||
|
|
||||||
/// If non-null, require the Lottie composition to have this width.
|
/// If non-null, require the Lottie composition to have this width.
|
||||||
///
|
///
|
||||||
/// If null, the composition will pick a size that best preserves its intrinsic
|
/// If null, the composition will pick a size that best preserves its intrinsic
|
||||||
@ -76,6 +83,7 @@ class RawLottie extends LeafRenderObjectWidget {
|
|||||||
delegates: delegates,
|
delegates: delegates,
|
||||||
enableMergePaths: options?.enableMergePaths,
|
enableMergePaths: options?.enableMergePaths,
|
||||||
progress: progress,
|
progress: progress,
|
||||||
|
frameRate: frameRate,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
fit: fit,
|
fit: fit,
|
||||||
@ -88,6 +96,7 @@ class RawLottie extends LeafRenderObjectWidget {
|
|||||||
renderObject
|
renderObject
|
||||||
..setComposition(composition,
|
..setComposition(composition,
|
||||||
progress: progress,
|
progress: progress,
|
||||||
|
frameRate: frameRate,
|
||||||
delegates: delegates,
|
delegates: delegates,
|
||||||
enableMergePaths: options?.enableMergePaths)
|
enableMergePaths: options?.enableMergePaths)
|
||||||
..width = width
|
..width = width
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import '../lottie.dart';
|
import '../lottie.dart';
|
||||||
|
import 'frame_rate.dart';
|
||||||
import 'lottie_drawable.dart';
|
import 'lottie_drawable.dart';
|
||||||
|
|
||||||
/// A Lottie animation in the render tree.
|
/// A Lottie animation in the render tree.
|
||||||
@ -9,10 +10,11 @@ import 'lottie_drawable.dart';
|
|||||||
/// constraints and preserves the composition's intrinsic aspect ratio.
|
/// constraints and preserves the composition's intrinsic aspect ratio.
|
||||||
class RenderLottie extends RenderBox {
|
class RenderLottie extends RenderBox {
|
||||||
RenderLottie({
|
RenderLottie({
|
||||||
LottieComposition composition,
|
@required LottieComposition composition,
|
||||||
LottieDelegates delegates,
|
LottieDelegates delegates,
|
||||||
bool enableMergePaths,
|
bool enableMergePaths,
|
||||||
double progress = 0.0,
|
double progress = 0.0,
|
||||||
|
FrameRate frameRate,
|
||||||
double width,
|
double width,
|
||||||
double height,
|
double height,
|
||||||
BoxFit fit,
|
BoxFit fit,
|
||||||
@ -21,7 +23,7 @@ class RenderLottie extends RenderBox {
|
|||||||
assert(progress != null && progress >= 0.0 && progress <= 1.0),
|
assert(progress != null && progress >= 0.0 && progress <= 1.0),
|
||||||
_drawable = composition != null
|
_drawable = composition != null
|
||||||
? (LottieDrawable(composition, enableMergePaths: enableMergePaths)
|
? (LottieDrawable(composition, enableMergePaths: enableMergePaths)
|
||||||
..setProgress(progress)
|
..setProgress(progress, frameRate: frameRate)
|
||||||
..delegates = delegates)
|
..delegates = delegates)
|
||||||
: null,
|
: null,
|
||||||
_width = width,
|
_width = width,
|
||||||
@ -34,6 +36,7 @@ class RenderLottie extends RenderBox {
|
|||||||
LottieDrawable _drawable;
|
LottieDrawable _drawable;
|
||||||
void setComposition(LottieComposition composition,
|
void setComposition(LottieComposition composition,
|
||||||
{@required double progress,
|
{@required double progress,
|
||||||
|
@required FrameRate frameRate,
|
||||||
@required LottieDelegates delegates,
|
@required LottieDelegates delegates,
|
||||||
bool enableMergePaths}) {
|
bool enableMergePaths}) {
|
||||||
enableMergePaths ??= false;
|
enableMergePaths ??= false;
|
||||||
@ -41,9 +44,11 @@ class RenderLottie extends RenderBox {
|
|||||||
var needsLayout = false;
|
var needsLayout = false;
|
||||||
var needsPaint = false;
|
var needsPaint = false;
|
||||||
if (composition == null) {
|
if (composition == null) {
|
||||||
_drawable = null;
|
if (_drawable != null) {
|
||||||
needsPaint = true;
|
_drawable = null;
|
||||||
needsLayout = true;
|
needsPaint = true;
|
||||||
|
needsLayout = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_drawable == null ||
|
if (_drawable == null ||
|
||||||
_drawable.composition != composition ||
|
_drawable.composition != composition ||
|
||||||
@ -54,7 +59,7 @@ class RenderLottie extends RenderBox {
|
|||||||
needsPaint = true;
|
needsPaint = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
needsPaint |= _drawable.setProgress(progress);
|
needsPaint |= _drawable.setProgress(progress, frameRate: frameRate);
|
||||||
|
|
||||||
if (_drawable.delegates != delegates) {
|
if (_drawable.delegates != delegates) {
|
||||||
_drawable.delegates = delegates;
|
_drawable.delegates = delegates;
|
||||||
|
35
pubspec.lock
@ -7,14 +7,14 @@ packages:
|
|||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "6.0.0"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.39.12"
|
version: "0.39.15"
|
||||||
archive:
|
archive:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -35,7 +35,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:
|
||||||
@ -49,7 +49,7 @@ packages:
|
|||||||
name: characters
|
name: characters
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.1.0-nullsafety"
|
||||||
charcode:
|
charcode:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -57,6 +57,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.3"
|
version: "1.1.3"
|
||||||
|
cli_util:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cli_util
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.4"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -70,7 +77,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.15.0-nullsafety"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -91,7 +98,7 @@ packages:
|
|||||||
name: csslib
|
name: csslib
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.16.1"
|
version: "0.16.2"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -150,14 +157,14 @@ packages:
|
|||||||
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: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.8"
|
version: "1.3.0-nullsafety"
|
||||||
mockito:
|
mockito:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -199,7 +206,7 @@ packages:
|
|||||||
name: pedantic
|
name: pedantic
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.0"
|
version: "1.9.2"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -225,7 +232,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:
|
||||||
@ -253,21 +260,21 @@ 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.3.0-nullsafety"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.8"
|
version: "2.1.0-nullsafety"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -283,4 +290,4 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.2.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.7.0 <3.0.0"
|
dart: ">=2.9.0-18.0 <2.9.0"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
name: lottie
|
name: lottie
|
||||||
description: Render After Effects animations natively on Flutter. This package is a pure Dart implementation of a Lottie player.
|
description: Render After Effects animations natively on Flutter. This package is a pure Dart implementation of a Lottie player.
|
||||||
version: 0.5.0
|
version: 0.6.0
|
||||||
homepage: https://github.com/xvrh/lottie-flutter
|
homepage: https://github.com/xvrh/lottie-flutter
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
14
test/frame_rate_test.dart
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:lottie/lottie.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('Frame rate round', () async {
|
||||||
|
var composition = await LottieComposition.fromBytes(
|
||||||
|
File('example/assets/LottieLogo1.json').readAsBytesSync());
|
||||||
|
expect(composition.roundProgress(0, frameRate: FrameRate.composition), 0);
|
||||||
|
expect(
|
||||||
|
composition.roundProgress(0.0001, frameRate: FrameRate.composition), 0);
|
||||||
|
expect(composition.roundProgress(0.0001, frameRate: FrameRate.max), 0.0001);
|
||||||
|
});
|
||||||
|
}
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 31 KiB |