Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
548c77dc45 |
11
CHANGELOG.md
@ -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]
|
||||
- Remove direct dependencies on dart:io to support Flutter Web
|
||||
|
||||
|
@ -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.
|
||||
|
||||
```dart
|
||||
import 'example/lib/examples/main.dart';
|
||||
import 'example/lib/main.dart';
|
||||
```
|
||||
|
||||
### 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: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());
|
||||
}
|
||||
void main() => runApp(MyApp());
|
||||
|
||||
class App extends StatelessWidget {
|
||||
class MyApp 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(
|
||||
body: ListView(
|
||||
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();
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// 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'),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
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
|
||||
|
||||
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_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
FlutterMacOS:
|
||||
:path: Flutter/ephemeral/.symlinks/flutter/darwin-x64
|
||||
:path: Flutter/ephemeral/.symlinks/flutter/darwin-x64-profile
|
||||
path_provider:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider/macos
|
||||
path_provider_macos:
|
||||
|
@ -21,7 +21,7 @@ packages:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.2"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -35,7 +35,7 @@ packages:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0-nullsafety"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -56,7 +56,7 @@ packages:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.14.12"
|
||||
version: "1.15.0-nullsafety"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -143,21 +143,21 @@ packages:
|
||||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.4.1"
|
||||
version: "0.6.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.6"
|
||||
version: "0.12.8"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.8"
|
||||
version: "1.3.0-nullsafety"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -199,7 +199,7 @@ packages:
|
||||
name: pedantic
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
version: "1.9.2"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -239,7 +239,7 @@ packages:
|
||||
name: stack_trace
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.3"
|
||||
version: "1.9.5"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -267,21 +267,21 @@ packages:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.16"
|
||||
version: "0.2.17"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.6"
|
||||
version: "1.3.0-nullsafety"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.8"
|
||||
version: "2.1.0-nullsafety"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -290,5 +290,5 @@ packages:
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
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"
|
||||
|
@ -33,6 +33,7 @@ void main() {
|
||||
composition: composition,
|
||||
controller: animation,
|
||||
delegates: LottieDelegates(values: [delegate]),
|
||||
addRepaintBoundary: false,
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
@ -45,6 +46,7 @@ void main() {
|
||||
composition: composition,
|
||||
controller: animation,
|
||||
delegates: LottieDelegates(values: []),
|
||||
addRepaintBoundary: false,
|
||||
),
|
||||
);
|
||||
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;
|
||||
|
||||
drawable
|
||||
..setProgress(progress)
|
||||
..setProgress(progress, frameRate: FrameRate.max)
|
||||
..draw(canvas, rect);
|
||||
|
||||
++index;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:lottie_example/main.dart';
|
||||
import 'package:lottie_example/main_app.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Main sample', (tester) async {
|
||||
|
@ -1,4 +1,5 @@
|
||||
export 'src/composition.dart' show LottieComposition;
|
||||
export 'src/frame_rate.dart' show FrameRate;
|
||||
export 'src/lottie.dart' show Lottie;
|
||||
export 'src/lottie_builder.dart' show LottieBuilder;
|
||||
export 'src/lottie_delegates.dart' show LottieDelegates;
|
||||
|
@ -3,6 +3,7 @@ import 'dart:typed_data';
|
||||
import 'package:archive/archive.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'frame_rate.dart';
|
||||
import 'logger.dart';
|
||||
import 'lottie_image_asset.dart';
|
||||
import 'model/font.dart';
|
||||
@ -133,9 +134,11 @@ class LottieComposition {
|
||||
Rectangle<int> get bounds => _bounds;
|
||||
|
||||
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 endFrame => _endFrame;
|
||||
@ -176,6 +179,24 @@ class LottieComposition {
|
||||
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
|
||||
String toString() {
|
||||
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);
|
||||
}
|
@ -2,6 +2,7 @@ import 'dart:typed_data';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import '../lottie.dart';
|
||||
import 'frame_rate.dart';
|
||||
import 'l.dart';
|
||||
import 'lottie_builder.dart';
|
||||
import 'options.dart';
|
||||
@ -22,19 +23,24 @@ class Lottie extends StatefulWidget {
|
||||
this.alignment,
|
||||
this.fit,
|
||||
bool animate,
|
||||
this.frameRate,
|
||||
bool repeat,
|
||||
bool reverse,
|
||||
this.delegates,
|
||||
this.options,
|
||||
bool addRepaintBoundary,
|
||||
}) : animate = animate ?? true,
|
||||
reverse = reverse ?? false,
|
||||
repeat = repeat ?? true,
|
||||
addRepaintBoundary = addRepaintBoundary ?? true,
|
||||
super(key: key);
|
||||
|
||||
/// Creates a widget that displays an [LottieComposition] obtained from an [AssetBundle].
|
||||
static LottieBuilder asset(String name,
|
||||
{Animation<double> controller,
|
||||
static LottieBuilder asset(
|
||||
String name, {
|
||||
Animation<double> controller,
|
||||
bool animate,
|
||||
FrameRate frameRate,
|
||||
bool repeat,
|
||||
bool reverse,
|
||||
LottieDelegates delegates,
|
||||
@ -48,10 +54,13 @@ class Lottie extends StatefulWidget {
|
||||
double height,
|
||||
BoxFit fit,
|
||||
Alignment alignment,
|
||||
String package}) =>
|
||||
String package,
|
||||
bool addRepaintBoundary,
|
||||
}) =>
|
||||
LottieBuilder.asset(
|
||||
name,
|
||||
controller: controller,
|
||||
frameRate: frameRate,
|
||||
animate: animate,
|
||||
repeat: repeat,
|
||||
reverse: reverse,
|
||||
@ -67,12 +76,14 @@ class Lottie extends StatefulWidget {
|
||||
fit: fit,
|
||||
alignment: alignment,
|
||||
package: package,
|
||||
addRepaintBoundary: addRepaintBoundary,
|
||||
);
|
||||
|
||||
/// Creates a widget that displays an [LottieComposition] obtained from a [File].
|
||||
static LottieBuilder file(
|
||||
Object /*io.File|html.File*/ file, {
|
||||
Animation<double> controller,
|
||||
FrameRate frameRate,
|
||||
bool animate,
|
||||
bool repeat,
|
||||
bool reverse,
|
||||
@ -86,10 +97,12 @@ class Lottie extends StatefulWidget {
|
||||
double height,
|
||||
BoxFit fit,
|
||||
Alignment alignment,
|
||||
bool addRepaintBoundary,
|
||||
}) =>
|
||||
LottieBuilder.file(
|
||||
file,
|
||||
controller: controller,
|
||||
frameRate: frameRate,
|
||||
animate: animate,
|
||||
repeat: repeat,
|
||||
reverse: reverse,
|
||||
@ -103,12 +116,14 @@ class Lottie extends StatefulWidget {
|
||||
height: height,
|
||||
fit: fit,
|
||||
alignment: alignment,
|
||||
addRepaintBoundary: addRepaintBoundary,
|
||||
);
|
||||
|
||||
/// Creates a widget that displays an [LottieComposition] obtained from a [Uint8List].
|
||||
static LottieBuilder memory(
|
||||
Uint8List bytes, {
|
||||
Animation<double> controller,
|
||||
FrameRate frameRate,
|
||||
bool animate,
|
||||
bool repeat,
|
||||
bool reverse,
|
||||
@ -122,10 +137,12 @@ class Lottie extends StatefulWidget {
|
||||
double height,
|
||||
BoxFit fit,
|
||||
Alignment alignment,
|
||||
bool addRepaintBoundary,
|
||||
}) =>
|
||||
LottieBuilder.memory(
|
||||
bytes,
|
||||
controller: controller,
|
||||
frameRate: frameRate,
|
||||
animate: animate,
|
||||
repeat: repeat,
|
||||
reverse: reverse,
|
||||
@ -139,12 +156,14 @@ class Lottie extends StatefulWidget {
|
||||
height: height,
|
||||
fit: fit,
|
||||
alignment: alignment,
|
||||
addRepaintBoundary: addRepaintBoundary,
|
||||
);
|
||||
|
||||
/// Creates a widget that displays an [LottieComposition] obtained from the network.
|
||||
static LottieBuilder network(
|
||||
String url, {
|
||||
Animation<double> controller,
|
||||
FrameRate frameRate,
|
||||
bool animate,
|
||||
bool repeat,
|
||||
bool reverse,
|
||||
@ -158,10 +177,12 @@ class Lottie extends StatefulWidget {
|
||||
double height,
|
||||
BoxFit fit,
|
||||
Alignment alignment,
|
||||
bool addRepaintBoundary,
|
||||
}) =>
|
||||
LottieBuilder.network(
|
||||
url,
|
||||
controller: controller,
|
||||
frameRate: frameRate,
|
||||
animate: animate,
|
||||
repeat: repeat,
|
||||
reverse: reverse,
|
||||
@ -175,6 +196,7 @@ class Lottie extends StatefulWidget {
|
||||
height: height,
|
||||
fit: fit,
|
||||
alignment: alignment,
|
||||
addRepaintBoundary: addRepaintBoundary,
|
||||
);
|
||||
|
||||
/// The Lottie composition to animate.
|
||||
@ -186,6 +208,14 @@ class Lottie extends StatefulWidget {
|
||||
/// with the properties [animate], [reverse]
|
||||
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
|
||||
/// Lottie animation should be played automatically (default to true).
|
||||
/// If there is an animation controller specified, this property has no effect.
|
||||
@ -249,6 +279,13 @@ class Lottie extends StatefulWidget {
|
||||
/// - enableMergePaths: Enable merge path support
|
||||
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 set traceEnabled(bool enabled) {
|
||||
L.traceEnabled = enabled;
|
||||
@ -303,18 +340,27 @@ class _LottieState extends State<Lottie> with TickerProviderStateMixin {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
Widget child = AnimatedBuilder(
|
||||
animation: _progressAnimation,
|
||||
builder: (context, _) => RawLottie(
|
||||
builder: (context, _) {
|
||||
return RawLottie(
|
||||
composition: widget.composition,
|
||||
delegates: widget.delegates,
|
||||
options: widget.options,
|
||||
progress: _progressAnimation.value,
|
||||
frameRate: widget.frameRate,
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
fit: widget.fit,
|
||||
alignment: widget.alignment,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (widget.addRepaintBoundary) {
|
||||
child = RepaintBoundary(child: child);
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import '../lottie.dart';
|
||||
import 'frame_rate.dart';
|
||||
import 'lottie.dart';
|
||||
import 'providers/asset_provider.dart';
|
||||
import 'providers/file_provider.dart';
|
||||
@ -35,6 +36,7 @@ class LottieBuilder extends StatefulWidget {
|
||||
Key key,
|
||||
@required this.lottie,
|
||||
this.controller,
|
||||
this.frameRate,
|
||||
this.animate,
|
||||
this.reverse,
|
||||
this.repeat,
|
||||
@ -46,6 +48,7 @@ class LottieBuilder extends StatefulWidget {
|
||||
this.height,
|
||||
this.fit,
|
||||
this.alignment,
|
||||
this.addRepaintBoundary,
|
||||
}) : assert(lottie != null),
|
||||
super(key: key);
|
||||
|
||||
@ -54,6 +57,7 @@ class LottieBuilder extends StatefulWidget {
|
||||
String src, {
|
||||
Map<String, String> headers,
|
||||
this.controller,
|
||||
this.frameRate,
|
||||
this.animate,
|
||||
this.reverse,
|
||||
this.repeat,
|
||||
@ -67,6 +71,7 @@ class LottieBuilder extends StatefulWidget {
|
||||
this.height,
|
||||
this.fit,
|
||||
this.alignment,
|
||||
this.addRepaintBoundary,
|
||||
}) : lottie = NetworkLottie(src,
|
||||
headers: headers, imageProviderFactory: imageProviderFactory),
|
||||
super(key: key);
|
||||
@ -84,6 +89,7 @@ class LottieBuilder extends StatefulWidget {
|
||||
LottieBuilder.file(
|
||||
Object /*io.File|html.File*/ file, {
|
||||
this.controller,
|
||||
this.frameRate,
|
||||
this.animate,
|
||||
this.reverse,
|
||||
this.repeat,
|
||||
@ -97,6 +103,7 @@ class LottieBuilder extends StatefulWidget {
|
||||
this.height,
|
||||
this.fit,
|
||||
this.alignment,
|
||||
this.addRepaintBoundary,
|
||||
}) : lottie = FileLottie(file, imageProviderFactory: imageProviderFactory),
|
||||
super(key: key);
|
||||
|
||||
@ -104,6 +111,7 @@ class LottieBuilder extends StatefulWidget {
|
||||
LottieBuilder.asset(
|
||||
String name, {
|
||||
this.controller,
|
||||
this.frameRate,
|
||||
this.animate,
|
||||
this.reverse,
|
||||
this.repeat,
|
||||
@ -119,6 +127,7 @@ class LottieBuilder extends StatefulWidget {
|
||||
this.fit,
|
||||
this.alignment,
|
||||
String package,
|
||||
this.addRepaintBoundary,
|
||||
}) : lottie = AssetLottie(name,
|
||||
bundle: bundle,
|
||||
package: package,
|
||||
@ -129,6 +138,7 @@ class LottieBuilder extends StatefulWidget {
|
||||
LottieBuilder.memory(
|
||||
Uint8List bytes, {
|
||||
this.controller,
|
||||
this.frameRate,
|
||||
this.animate,
|
||||
this.reverse,
|
||||
this.repeat,
|
||||
@ -142,6 +152,7 @@ class LottieBuilder extends StatefulWidget {
|
||||
this.height,
|
||||
this.fit,
|
||||
this.alignment,
|
||||
this.addRepaintBoundary,
|
||||
}) : lottie =
|
||||
MemoryLottie(bytes, imageProviderFactory: imageProviderFactory),
|
||||
super(key: key);
|
||||
@ -160,6 +171,11 @@ class LottieBuilder extends StatefulWidget {
|
||||
/// Lottie animation.
|
||||
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
|
||||
/// Lottie animation should be played automatically (default to true).
|
||||
/// If there is an animation controller specified, this property has no effect.
|
||||
@ -320,6 +336,13 @@ class LottieBuilder extends StatefulWidget {
|
||||
/// relative to text direction.
|
||||
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
|
||||
_LottieBuilderState createState() => _LottieBuilderState();
|
||||
|
||||
@ -383,6 +406,7 @@ class _LottieBuilderState extends State<LottieBuilder> {
|
||||
Widget result = Lottie(
|
||||
composition: composition,
|
||||
controller: widget.controller,
|
||||
frameRate: widget.frameRate,
|
||||
animate: widget.animate,
|
||||
reverse: widget.reverse,
|
||||
repeat: widget.repeat,
|
||||
@ -392,6 +416,7 @@ class _LottieBuilderState extends State<LottieBuilder> {
|
||||
height: widget.height,
|
||||
fit: widget.fit,
|
||||
alignment: widget.alignment,
|
||||
addRepaintBoundary: widget.addRepaintBoundary,
|
||||
);
|
||||
|
||||
if (widget.frameBuilder != null) {
|
||||
|
@ -3,7 +3,7 @@ import 'lottie_drawable.dart';
|
||||
import 'value_delegate.dart';
|
||||
|
||||
// TODO(xha): recognize style Bold, Medium, Regular, SemiBold, etc...
|
||||
TextStyle _defaultTextStyleDelegate(LottieFontStyle font) =>
|
||||
TextStyle defaultTextStyleDelegate(LottieFontStyle font) =>
|
||||
TextStyle(fontFamily: font.fontFamily);
|
||||
|
||||
@immutable
|
||||
@ -49,7 +49,7 @@ class LottieDelegates {
|
||||
this.text,
|
||||
TextStyle Function(LottieFontStyle) textStyle,
|
||||
this.values,
|
||||
}) : textStyle = textStyle ?? _defaultTextStyleDelegate;
|
||||
}) : textStyle = textStyle;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
|
@ -2,6 +2,7 @@ import 'dart:ui' as ui;
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'composition.dart';
|
||||
import 'frame_rate.dart';
|
||||
import 'lottie_delegates.dart';
|
||||
import 'model/key_path.dart';
|
||||
import 'model/layer/composition_layer.dart';
|
||||
@ -43,26 +44,32 @@ class LottieDrawable {
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
double get progress => _progress;
|
||||
double _progress = 0.0;
|
||||
bool setProgress(double value) {
|
||||
double get progress => _progress ?? 0.0;
|
||||
double _progress;
|
||||
bool setProgress(double value, {FrameRate frameRate}) {
|
||||
frameRate ??= FrameRate.composition;
|
||||
var roundedProgress =
|
||||
composition.roundProgress(value, frameRate: frameRate);
|
||||
if (roundedProgress != _progress) {
|
||||
_isDirty = false;
|
||||
_progress = value;
|
||||
_compositionLayer.setProgress(value);
|
||||
_progress = roundedProgress;
|
||||
_compositionLayer.setProgress(roundedProgress);
|
||||
return _isDirty;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LottieDelegates get delegates => _delegates;
|
||||
set delegates(LottieDelegates delegates) {
|
||||
delegates ??= LottieDelegates();
|
||||
if (_delegates != delegates) {
|
||||
_delegates = delegates;
|
||||
_updateValueDelegates(delegates.values);
|
||||
_updateValueDelegates(delegates?.values);
|
||||
}
|
||||
}
|
||||
|
||||
bool get useTextGlyphs {
|
||||
return delegates.text == null && composition.characters.isNotEmpty;
|
||||
return delegates?.text == null && composition.characters.isNotEmpty;
|
||||
}
|
||||
|
||||
ui.Image getImageAsset(String ref) {
|
||||
@ -75,8 +82,8 @@ class LottieDrawable {
|
||||
}
|
||||
|
||||
TextStyle getTextStyle(String font, String style) {
|
||||
return _delegates
|
||||
.textStyle(LottieFontStyle(fontFamily: font, style: style));
|
||||
return (_delegates?.textStyle ?? defaultTextStyleDelegate)(
|
||||
LottieFontStyle(fontFamily: font, style: style));
|
||||
}
|
||||
|
||||
List<ValueDelegate> _valueDelegates = <ValueDelegate>[];
|
||||
|
@ -232,7 +232,7 @@ class TextLayer extends BaseLayer {
|
||||
return;
|
||||
}
|
||||
var text = documentData.text;
|
||||
var textDelegate = lottieDrawable.delegates.text;
|
||||
var textDelegate = lottieDrawable.delegates?.text;
|
||||
if (textDelegate != null) {
|
||||
text = textDelegate(text);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import '../lottie.dart';
|
||||
import 'frame_rate.dart';
|
||||
import 'lottie_drawable.dart';
|
||||
import 'render_lottie.dart';
|
||||
|
||||
@ -15,6 +16,7 @@ class RawLottie extends LeafRenderObjectWidget {
|
||||
this.delegates,
|
||||
this.options,
|
||||
double progress,
|
||||
this.frameRate,
|
||||
this.width,
|
||||
this.height,
|
||||
this.fit,
|
||||
@ -34,6 +36,11 @@ class RawLottie extends LeafRenderObjectWidget {
|
||||
/// The progress of the Lottie animation (between 0.0 and 1.0).
|
||||
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 null, the composition will pick a size that best preserves its intrinsic
|
||||
@ -76,6 +83,7 @@ class RawLottie extends LeafRenderObjectWidget {
|
||||
delegates: delegates,
|
||||
enableMergePaths: options?.enableMergePaths,
|
||||
progress: progress,
|
||||
frameRate: frameRate,
|
||||
width: width,
|
||||
height: height,
|
||||
fit: fit,
|
||||
@ -88,6 +96,7 @@ class RawLottie extends LeafRenderObjectWidget {
|
||||
renderObject
|
||||
..setComposition(composition,
|
||||
progress: progress,
|
||||
frameRate: frameRate,
|
||||
delegates: delegates,
|
||||
enableMergePaths: options?.enableMergePaths)
|
||||
..width = width
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import '../lottie.dart';
|
||||
import 'frame_rate.dart';
|
||||
import 'lottie_drawable.dart';
|
||||
|
||||
/// A Lottie animation in the render tree.
|
||||
@ -9,10 +10,11 @@ import 'lottie_drawable.dart';
|
||||
/// constraints and preserves the composition's intrinsic aspect ratio.
|
||||
class RenderLottie extends RenderBox {
|
||||
RenderLottie({
|
||||
LottieComposition composition,
|
||||
@required LottieComposition composition,
|
||||
LottieDelegates delegates,
|
||||
bool enableMergePaths,
|
||||
double progress = 0.0,
|
||||
FrameRate frameRate,
|
||||
double width,
|
||||
double height,
|
||||
BoxFit fit,
|
||||
@ -21,7 +23,7 @@ class RenderLottie extends RenderBox {
|
||||
assert(progress != null && progress >= 0.0 && progress <= 1.0),
|
||||
_drawable = composition != null
|
||||
? (LottieDrawable(composition, enableMergePaths: enableMergePaths)
|
||||
..setProgress(progress)
|
||||
..setProgress(progress, frameRate: frameRate)
|
||||
..delegates = delegates)
|
||||
: null,
|
||||
_width = width,
|
||||
@ -34,6 +36,7 @@ class RenderLottie extends RenderBox {
|
||||
LottieDrawable _drawable;
|
||||
void setComposition(LottieComposition composition,
|
||||
{@required double progress,
|
||||
@required FrameRate frameRate,
|
||||
@required LottieDelegates delegates,
|
||||
bool enableMergePaths}) {
|
||||
enableMergePaths ??= false;
|
||||
@ -41,9 +44,11 @@ class RenderLottie extends RenderBox {
|
||||
var needsLayout = false;
|
||||
var needsPaint = false;
|
||||
if (composition == null) {
|
||||
if (_drawable != null) {
|
||||
_drawable = null;
|
||||
needsPaint = true;
|
||||
needsLayout = true;
|
||||
}
|
||||
} else {
|
||||
if (_drawable == null ||
|
||||
_drawable.composition != composition ||
|
||||
@ -54,7 +59,7 @@ class RenderLottie extends RenderBox {
|
||||
needsPaint = true;
|
||||
}
|
||||
|
||||
needsPaint |= _drawable.setProgress(progress);
|
||||
needsPaint |= _drawable.setProgress(progress, frameRate: frameRate);
|
||||
|
||||
if (_drawable.delegates != delegates) {
|
||||
_drawable.delegates = delegates;
|
||||
|
35
pubspec.lock
@ -7,14 +7,14 @@ packages:
|
||||
name: _fe_analyzer_shared
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "6.0.0"
|
||||
analyzer:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: analyzer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.39.12"
|
||||
version: "0.39.15"
|
||||
archive:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -35,7 +35,7 @@ packages:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.2"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -49,7 +49,7 @@ packages:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0-nullsafety"
|
||||
charcode:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -57,6 +57,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.4"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -70,7 +77,7 @@ packages:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.14.12"
|
||||
version: "1.15.0-nullsafety"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -91,7 +98,7 @@ packages:
|
||||
name: csslib
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.16.1"
|
||||
version: "0.16.2"
|
||||
dart_style:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -150,14 +157,14 @@ packages:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.6"
|
||||
version: "0.12.8"
|
||||
meta:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.8"
|
||||
version: "1.3.0-nullsafety"
|
||||
mockito:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -199,7 +206,7 @@ packages:
|
||||
name: pedantic
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
version: "1.9.2"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -225,7 +232,7 @@ packages:
|
||||
name: stack_trace
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.3"
|
||||
version: "1.9.5"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -253,21 +260,21 @@ packages:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.16"
|
||||
version: "0.2.17"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.6"
|
||||
version: "1.3.0-nullsafety"
|
||||
vector_math:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.8"
|
||||
version: "2.1.0-nullsafety"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -283,4 +290,4 @@ packages:
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
sdks:
|
||||
dart: ">=2.7.0 <3.0.0"
|
||||
dart: ">=2.9.0-18.0 <2.9.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
name: lottie
|
||||
description: Render After Effects animations natively on Flutter. This package is a pure Dart implementation of a Lottie player.
|
||||
version: 0.5.1
|
||||
version: 0.6.0
|
||||
homepage: https://github.com/xvrh/lottie-flutter
|
||||
|
||||
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 |