Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
0715f6a402 | |||
7e81ec3f69 |
@ -1,3 +1,9 @@
|
||||
## [0.3.6]
|
||||
- Export the `Marker` class
|
||||
|
||||
## [0.3.5]
|
||||
- Fix a bug with a wrongly clipped rectangle.
|
||||
|
||||
## [0.3.4]
|
||||
- Fix a bug with dashed path
|
||||
|
||||
|
1
example/assets/TwitterHeartButton.json
Normal file
2534
example/assets/weather/hurricane.json
Normal file
@ -5,23 +5,15 @@ void main() async {
|
||||
runApp(App());
|
||||
}
|
||||
|
||||
class App extends StatefulWidget {
|
||||
class App extends StatelessWidget {
|
||||
const App({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AppState createState() => _AppState();
|
||||
}
|
||||
|
||||
class _AppState extends State<App> with TickerProviderStateMixin {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
color: Colors.lightBlue,
|
||||
home: Scaffold(
|
||||
backgroundColor: Colors.lightBlue,
|
||||
appBar: AppBar(
|
||||
title: Text(''),
|
||||
),
|
||||
body: Center(
|
||||
child: SizedBox(
|
||||
width: 300,
|
||||
|
122
example/lib/examples/markers.dart
Normal file
@ -0,0 +1,122 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lottie/lottie.dart';
|
||||
|
||||
/// This example shows how to play the animation between two markers.
|
||||
/// It is based on this article for lottie-ios:
|
||||
/// https://medium.com/swlh/controlling-lottie-animation-with-markers-5e9035d94623
|
||||
void main() async {
|
||||
runApp(App());
|
||||
}
|
||||
|
||||
class App extends StatefulWidget {
|
||||
const App({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AppState createState() => _AppState();
|
||||
}
|
||||
|
||||
class _AppState extends State<App> with TickerProviderStateMixin {
|
||||
Future<LottieComposition> _composition;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_composition = AssetLottie('assets/TwitterHeartButton.json').load();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData.dark(),
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Markers'),
|
||||
),
|
||||
body: FutureBuilder<LottieComposition>(
|
||||
future: _composition,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) return ErrorWidget(snapshot.error);
|
||||
if (!snapshot.hasData) return CircularProgressIndicator();
|
||||
return _LottieDetails(snapshot.data);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _LottieDetails extends StatefulWidget {
|
||||
final LottieComposition composition;
|
||||
|
||||
const _LottieDetails(this.composition, {Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_LottieDetailsState createState() => _LottieDetailsState();
|
||||
}
|
||||
|
||||
class _LottieDetailsState extends State<_LottieDetails>
|
||||
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 ListView(
|
||||
children: [
|
||||
Lottie(
|
||||
composition: widget.composition,
|
||||
controller: _controller,
|
||||
height: 150,
|
||||
),
|
||||
ListTile(
|
||||
title: Text('Composition start frame'),
|
||||
trailing: Text(widget.composition.startFrame.toStringAsFixed(1)),
|
||||
),
|
||||
ListTile(
|
||||
title: Text('Composition duration'),
|
||||
trailing: Text(widget.composition.durationFrames.toStringAsFixed(1)),
|
||||
),
|
||||
RaisedButton(
|
||||
child: Text('touchDownEnd - touchUpCancel'),
|
||||
onPressed: () => _playBetween('touchDownEnd', 'touchUpCancel'),
|
||||
),
|
||||
RaisedButton(
|
||||
child: Text('touchDownStart - touchDownEnd'),
|
||||
onPressed: () => _playBetween('touchDownStart', 'touchDownEnd'),
|
||||
),
|
||||
RaisedButton(
|
||||
child: Text('touchDownEnd - touchUpEnd'),
|
||||
onPressed: () => _playBetween('touchDownEnd', 'touchUpEnd'),
|
||||
),
|
||||
for (var marker in widget.composition.markers)
|
||||
ListTile(
|
||||
title: Text(marker.name),
|
||||
subtitle: Text(
|
||||
'${marker.startFrame.toStringAsFixed(1)} ${marker.durationFrames.toStringAsFixed(1)}'),
|
||||
trailing: Text(
|
||||
'[${marker.start.toStringAsFixed(2)}-${marker.end.toStringAsFixed(2)}]'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _playBetween(String marker1, String marker2) {
|
||||
var start = widget.composition.getMarker(marker1).start;
|
||||
var end = widget.composition.getMarker(marker2).start;
|
||||
|
||||
_controller.value = start;
|
||||
_controller.animateTo(end,
|
||||
duration: widget.composition.duration * (end - start).abs());
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ EXTERNAL SOURCES:
|
||||
SPEC CHECKSUMS:
|
||||
FlutterMacOS: 15bea8a44d2fa024068daa0140371c020b4b6ff9
|
||||
path_provider: e0848572d1d38b9a7dd099e79cf83f5b7e2cde9f
|
||||
path_provider_macos: adb94ae6c253c45ef2aac146fbf1f4504d74b0f8
|
||||
path_provider_macos: a0a3fd666cb7cd0448e936fb4abad4052961002b
|
||||
|
||||
PODFILE CHECKSUM: d8ba9b3e9e93c62c74a660b46c6fcb09f03991a7
|
||||
|
||||
|
@ -43,6 +43,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -64,6 +71,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -102,13 +116,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.12"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -122,7 +129,7 @@ packages:
|
||||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.3.4"
|
||||
version: "0.3.6"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -143,7 +150,7 @@ packages:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.4"
|
||||
version: "1.7.0"
|
||||
path_provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -172,13 +179,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -193,13 +193,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -261,13 +254,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.8"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.6.1"
|
||||
sdks:
|
||||
dart: ">=2.7.0 <3.0.0"
|
||||
flutter: ">=1.12.13+hotfix.5 <2.0.0"
|
||||
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
BIN
example/test/goldens/all/twitterheartbutton.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
example/test/goldens/all/weather/hurricane.png
Normal file
After Width: | Height: | Size: 70 KiB |
@ -4,6 +4,7 @@ export 'src/lottie_builder.dart' show LottieBuilder;
|
||||
export 'src/lottie_delegates.dart' show LottieDelegates;
|
||||
export 'src/lottie_drawable.dart' show LottieDrawable, LottieFontStyle;
|
||||
export 'src/lottie_image_asset.dart' show LottieImageAsset;
|
||||
export 'src/model/marker.dart' show Marker;
|
||||
export 'src/providers/asset_provider.dart' show AssetLottie;
|
||||
export 'src/providers/file_provider.dart' show FileLottie;
|
||||
export 'src/providers/lottie_provider.dart' show LottieProvider;
|
||||
|
@ -1,26 +1,23 @@
|
||||
import 'package:meta/meta.dart';
|
||||
import '../../lottie.dart';
|
||||
|
||||
class Marker {
|
||||
static const String _carriageReturn = '\r';
|
||||
|
||||
final LottieComposition _composition;
|
||||
final String name;
|
||||
final double startFrame;
|
||||
final double durationFrames;
|
||||
|
||||
Marker(this.name, {@required this.startFrame, @required this.durationFrames});
|
||||
Marker(this._composition, this.name,
|
||||
{@required this.startFrame, @required this.durationFrames});
|
||||
|
||||
bool matchesName(String name) {
|
||||
if (this.name.toLowerCase() == name.toLowerCase()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// It is easy for a designer to accidentally include an extra newline which will cause the name to not match what they would
|
||||
// expect. This is a convenience to precent unneccesary confusion.
|
||||
if (this.name.endsWith(_carriageReturn) &&
|
||||
this.name.substring(0, this.name.length - 1).toLowerCase() ==
|
||||
name.toLowerCase()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return this.name.trim().toLowerCase() == name.toLowerCase();
|
||||
}
|
||||
|
||||
double get start =>
|
||||
(startFrame - _composition.startFrame) / _composition.durationFrames;
|
||||
|
||||
double get end =>
|
||||
(startFrame + durationFrames - _composition.startFrame) /
|
||||
_composition.durationFrames;
|
||||
}
|
||||
|
@ -254,8 +254,8 @@ class LottieCompositionParser {
|
||||
}
|
||||
}
|
||||
reader.endObject();
|
||||
markers.add(
|
||||
Marker(comment, startFrame: frame, durationFrames: durationFrames));
|
||||
markers.add(Marker(composition, comment,
|
||||
startFrame: frame, durationFrames: durationFrames));
|
||||
}
|
||||
reader.endArray();
|
||||
}
|
||||
|
@ -34,28 +34,20 @@ extension Matrix4Extension on Matrix4 {
|
||||
}
|
||||
|
||||
Rect mapRect(Rect rect) {
|
||||
var topLeft = Vector3(rect.left, rect.top, 0.0)..applyMatrix4(this);
|
||||
var topRight = Vector3(rect.right, rect.top, 0.0)..applyMatrix4(this);
|
||||
var bottomLeft = Vector3(rect.left, rect.bottom, 0.0)..applyMatrix4(this);
|
||||
var bottomRight = Vector3(rect.right, rect.bottom, 0.0)..applyMatrix4(this);
|
||||
|
||||
var newLeft = min(topLeft.x, bottomLeft.x);
|
||||
var newTop = min(topLeft.y, topRight.y);
|
||||
var newRight = max(topRight.x, bottomRight.x);
|
||||
var newBottom = max(bottomLeft.y, bottomRight.y);
|
||||
|
||||
return Rect.fromLTRB(newLeft, newTop, newRight, newBottom);
|
||||
return MatrixUtils.transformRect(this, rect);
|
||||
}
|
||||
|
||||
/// Apply this matrix to the array of 2D points, and write the transformed points back into the
|
||||
/// array
|
||||
///
|
||||
/// @param pts The array [x0, y0, x1, y1, ...] of points to transform.
|
||||
void mapPoints(List<double> array, [int offset]) {
|
||||
void mapPoints(List<double> array) {
|
||||
for (var i = 0; i < array.length; i += 2) {
|
||||
final v = Vector3(array[i], array[i + 1], 0.0)..applyMatrix4(this);
|
||||
array[i] = v.storage[0];
|
||||
array[i + 1] = v.storage[1];
|
||||
final v =
|
||||
MatrixUtils.transformPoint(this, Offset(array[i], array[i + 1]));
|
||||
|
||||
array[i] = v.dx;
|
||||
array[i + 1] = v.dy;
|
||||
}
|
||||
}
|
||||
|
||||
|
44
pubspec.lock
@ -57,6 +57,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
collection:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -92,6 +99,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.6"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -116,13 +130,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.14.0+3"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.12"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -185,7 +192,7 @@ packages:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.4"
|
||||
version: "1.7.0"
|
||||
pedantic:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -193,13 +200,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -207,13 +207,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.4.4"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -282,13 +275,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.9.7+15"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.6.1"
|
||||
yaml:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
@ -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.3.4
|
||||
version: 0.3.6
|
||||
homepage: https://github.com/xvrh/lottie-flutter
|
||||
|
||||
environment:
|
||||
|