Compare commits

..

5 Commits

Author SHA1 Message Date
78aeed452f Fix bug with repeater (#29) 2020-03-16 09:10:35 +01:00
af9b69326a Dash path effect (#27) 2020-03-12 23:16:41 +01:00
511094262f Update example to latest version 2020-03-05 21:11:05 +01:00
62a60208b2 Bump version 2020-03-05 21:10:37 +01:00
c0c3ecbf5e Specify version range on the dependency on characters (#26) 2020-03-05 20:56:17 +01:00
79 changed files with 1742 additions and 60 deletions

View File

@ -1,4 +1,13 @@
## [0.3.0] - 2020-03-02
## [0.3.2] - 2020-03-16
- Fix a bug with "repeater" content
## [0.3.1] - 2020-03-05
- Support dashed path
## [0.3.0+1] - 2020-03-05
- Specify a version range for the dependency on `characters`.
## [0.3.0] - 2020-03-05
- Add `LottieDelegates` a group of options to customize the lottie animation at runtime.
ie: Dynamically modify color, position, size, text... of every elements of the animation.
- Correctly display Linear and Radial Gradients

View File

@ -83,7 +83,7 @@ class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
body: ListView(
children: [
Lottie.network(
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/sample_app/assets/Mobilo/C.json',
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/C.json',
controller: _controller,
onLoaded: (composition) {
// Configure the AnimationController with the duration of the
@ -243,9 +243,8 @@ class _Animation extends StatelessWidget {
## Limitations
This is a new library so usability, documentation and performance are still work in progress.
The following features are not yet implemented:
- Dash path effects
- Transforms on gradients (stroke and fills)
Only the [supported features of Lottie Android](https://airbnb.io/lottie/#/supported-features)
are supported in this port.
## Flutter Web
Run the app with `flutter run -d Chrome --dart-define=FLUTTER_WEB_USE_SKIA=true --release`

View File

@ -74,9 +74,8 @@ import 'example/lib/examples/simple_dynamic_properties.dart#example';
## Limitations
This is a new library so usability, documentation and performance are still work in progress.
The following features are not yet implemented:
- Dash path effects
- Transforms on gradients (stroke and fills)
Only the [supported features of Lottie Android](https://airbnb.io/lottie/#/supported-features)
are supported in this port.
## Flutter Web
Run the app with `flutter run -d Chrome --dart-define=FLUTTER_WEB_USE_SKIA=true --release`

View File

@ -3,6 +3,7 @@ analyzer:
errors:
strong-mode:
implicit-casts: false
implicit-dynamic: false
linter:
rules:
avoid_renaming_method_parameters: true

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@ class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
body: ListView(
children: [
Lottie.network(
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/sample_app/assets/Mobilo/C.json',
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/C.json',
controller: _controller,
onLoaded: (composition) {
// Configure the AnimationController with the duration of the

View File

@ -2,14 +2,13 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:lottie/lottie.dart';
import 'package:lottie/src/l.dart';
import 'src/all_files.g.dart';
void main() {
Logger.root
..level = Level.ALL
..onRecord.listen(print);
L.setTraceEnabled(true);
Lottie.traceEnabled = true;
runApp(App());
}
@ -43,8 +42,8 @@ class App extends StatelessWidget {
),
),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Detail(assetName)));
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (context) => Detail(assetName)));
},
);
},

View File

@ -216,9 +216,9 @@ final files = [
'assets/lottiefiles/light.json',
'assets/lottiefiles/lightsaber.json',
'assets/lottiefiles/little_girl_jumping_-_loader.json',
'assets/lottiefiles/loading copy.json',
'assets/lottiefiles/loading disc.json',
'assets/lottiefiles/loading.json',
'assets/lottiefiles/loading_copy.json',
'assets/lottiefiles/loading_disc.json',
'assets/lottiefiles/loading_semicircle.json',
'assets/lottiefiles/location.json',
'assets/lottiefiles/location_marker.json',

View File

@ -108,7 +108,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.3.0"
version: "0.3.2"
matcher:
dependency: transitive
description:

View File

@ -0,0 +1,23 @@
import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lottie/lottie.dart';
import 'package:path/path.dart' as p;
import 'utils.dart';
void main() {
testWidgets('Animations with stroke', (tester) async {
var size = Size(500, 400);
tester.binding.window.physicalSizeTestValue = size;
tester.binding.window.devicePixelRatioTestValue = 1.0;
var composition = await LottieComposition.fromBytes(
File('assets/17297-fireworks.json').readAsBytesSync());
await tester.pumpWidget(FilmStrip(composition, size: size));
await expectLater(find.byType(FilmStrip),
matchesGoldenFile(p.join('goldens/fireworks.png')));
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -0,0 +1,37 @@
import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lottie/lottie.dart';
import 'package:path/path.dart' as p;
import 'utils.dart';
void main() {
testWidgets('Animations with stroke', (tester) async {
var size = Size(500, 400);
tester.binding.window.physicalSizeTestValue = size;
tester.binding.window.devicePixelRatioTestValue = 1.0;
for (var asset in [
'assets/Tests/Stroke.json',
'assets/lottiefiles/loading_disc.json',
'assets/Mobilo/G.json',
'assets/lottiefiles/truecosmos.json',
'assets/lottiefiles/intelia_logo_animation.json',
'assets/lottiefiles/landing_page.json',
'assets/lottiefiles/permission.json',
'assets/lottiefiles/little_girl_jumping_-_loader.json',
'assets/lottiefiles/playing.json',
'assets/lottiefiles/win_result_2.json',
]) {
var composition =
await LottieComposition.fromBytes(File(asset).readAsBytesSync());
await tester.pumpWidget(FilmStrip(composition, size: size));
var fileName = '${p.basenameWithoutExtension(asset)}.png'.toLowerCase();
await expectLater(find.byType(FilmStrip),
matchesGoldenFile(p.join('goldens/strokes', fileName)));
}
});
}

51
example/test/utils.dart Normal file
View File

@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
class FilmStrip extends StatelessWidget {
final LottieComposition composition;
final Size size;
const FilmStrip(this.composition, {Key key, @required this.size})
: super(key: key);
@override
Widget build(BuildContext context) {
return CustomPaint(
size: size,
painter: _CustomerPainter(composition),
);
}
}
class _CustomerPainter extends CustomPainter {
static const _columns = 5;
final LottieComposition composition;
_CustomerPainter(this.composition);
@override
void paint(Canvas canvas, Size size) {
var thumbSize = Size(size.width / _columns, size.width / _columns);
var drawable = LottieDrawable(composition);
var index = 0;
for (var progress = 0.0; progress <= 1; progress += 0.05) {
var x = index % _columns;
var y = index ~/ _columns;
var rect = Offset(x * thumbSize.width, y.toDouble() * thumbSize.height) &
thumbSize;
drawable
..setProgress(progress)
..draw(canvas, rect);
++index;
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}

View File

@ -11,6 +11,7 @@ import '../../model/content/shape_trim_path.dart';
import '../../model/key_path.dart';
import '../../model/layer/base_layer.dart';
import '../../utils.dart';
import '../../utils/dash_path.dart';
import '../../utils/misc.dart';
import '../../utils/utils.dart';
import '../../value/lottie_value_callback.dart';
@ -132,7 +133,6 @@ abstract class BaseStrokeContent
L.endSection('StrokeContent#draw');
return;
}
_applyDashPatternIfNeeded(parentMatrix);
if (_colorFilterAnimation != null) {
paint.colorFilter = _colorFilterAnimation.value;
@ -152,7 +152,7 @@ abstract class BaseStrokeContent
}
L.endSection('StrokeContent#buildPath');
L.beginSection('StrokeContent#drawPath');
canvas.drawPath(_path, paint);
canvas.drawPath(_withDashPattern(_path, parentMatrix), paint);
L.endSection('StrokeContent#drawPath');
}
}
@ -199,13 +199,13 @@ abstract class BaseStrokeContent
}
var endValue = min((endLength - totalLength) / length, 1).toDouble();
Utils.applyTrimPathIfNeeded(_trimPathPath, startValue, endValue, 0.0);
canvas.drawPath(_trimPathPath, paint);
canvas.drawPath(_withDashPattern(_trimPathPath, parentMatrix), paint);
} else if (currentLength + length < startLength ||
currentLength > endLength) {
// Do nothing
} else if (currentLength + length <= endLength &&
startLength < currentLength) {
canvas.drawPath(_trimPathPath, paint);
canvas.drawPath(_withDashPattern(_trimPathPath, parentMatrix), paint);
} else {
double startValue;
if (startLength < currentLength) {
@ -220,7 +220,7 @@ abstract class BaseStrokeContent
endValue = (endLength - currentLength) / length;
}
Utils.applyTrimPathIfNeeded(_trimPathPath, startValue, endValue, 0);
canvas.drawPath(_trimPathPath, paint);
canvas.drawPath(_withDashPattern(_trimPathPath, parentMatrix), paint);
}
currentLength += length;
}
@ -250,11 +250,11 @@ abstract class BaseStrokeContent
return bounds;
}
void _applyDashPatternIfNeeded(Matrix4 parentMatrix) {
Path _withDashPattern(Path path, Matrix4 parentMatrix) {
L.beginSection('StrokeContent#applyDashPattern');
if (_dashPatternAnimations.isEmpty) {
L.endSection('StrokeContent#applyDashPattern');
return;
return path;
}
var scale = parentMatrix.getScale();
@ -275,12 +275,12 @@ abstract class BaseStrokeContent
}
_dashPatternValues[i] *= scale;
}
//TODO(xha): implement DashPathEffect with https://github.com/dnfield/flutter_path_drawing/blob/master/lib/src/dash_path.dart
// var offset = _dashPatternOffsetAnimation == null
// ? 0.0
// : _dashPatternOffsetAnimation.value * scale;
//paint.setPathEffect(DashPathEffect(_dashPatternValues, offset));
var newPath =
dashPath(path, dashArray: CircularIntervalList(_dashPatternValues));
L.endSection('StrokeContent#applyDashPattern');
return newPath;
}
@override

View File

@ -71,10 +71,8 @@ class RepeaterContent
var newContents = <Content>[];
while (index >= 0) {
var content = contents[index];
if (content is PathContent) {
newContents.add(content);
contents.removeAt(index);
}
--index;
}
newContents = newContents.reversed.toList();

View File

@ -35,7 +35,7 @@ class TransformKeyframeAnimation {
final Matrix4 _skewMatrix3;
BaseKeyframeAnimation<Offset, Offset> /*?*/ _anchorPoint;
BaseKeyframeAnimation<dynamic, Offset> /*?*/ _position;
BaseKeyframeAnimation<Offset, Offset> /*?*/ _position;
BaseKeyframeAnimation<Offset, Offset> /*?*/ _scale;
BaseKeyframeAnimation<double, double> /*?*/ _rotation;
DoubleKeyframeAnimation /*?*/ _skew;
@ -44,12 +44,11 @@ class TransformKeyframeAnimation {
BaseKeyframeAnimation<int, int> /*?*/ _opacity;
BaseKeyframeAnimation<int, int> /*?*/ get opacity => _opacity;
BaseKeyframeAnimation<dynamic, double> /*?*/ _startOpacity;
BaseKeyframeAnimation<dynamic, double> /*?*/ get startOpacity =>
_startOpacity;
BaseKeyframeAnimation<double, double> /*?*/ _startOpacity;
BaseKeyframeAnimation<double, double> /*?*/ get startOpacity => _startOpacity;
BaseKeyframeAnimation<dynamic, double> /*?*/ _endOpacity;
BaseKeyframeAnimation<dynamic, double> /*?*/ get endOpacity => _endOpacity;
BaseKeyframeAnimation<double, double> /*?*/ _endOpacity;
BaseKeyframeAnimation<double, double> /*?*/ get endOpacity => _endOpacity;
void addAnimationsToLayer(BaseLayer layer) {
layer.addAnimation(_opacity);
@ -159,23 +158,25 @@ class TransformKeyframeAnimation {
Matrix4 getMatrixForRepeater(double amount) {
final position = _position?.value;
final scale = _scale?.value;
final rotation = _rotation?.value;
_matrix.setIdentity();
if (position != null) {
_matrix.translate(position.dx, position.dy);
_matrix.translate(position.dx * amount, position.dy * amount);
}
if (scale != null) {
_matrix.scale(scale.dx, scale.dy);
_matrix.scale(
pow(scale.dx, amount).toDouble(), pow(scale.dy, amount).toDouble());
}
if (rotation != null) {
final anchorPoint = _anchorPoint?.value ?? Offset.zero;
_matrix.translate(anchorPoint.dx, anchorPoint.dy);
_matrix.rotateZ(rotation * pi / 180.0);
_matrix.translate(-anchorPoint.dx, -anchorPoint.dy);
if (_rotation != null) {
var rotation = _rotation.value;
var anchorPoint = _anchorPoint?.value;
_matrix.rotate(
Vector3(anchorPoint == null ? 0.0 : anchorPoint.dx,
anchorPoint == null ? 0.0 : anchorPoint.dy, 1.0),
radians(rotation * amount));
}
return _matrix;

View File

@ -1,3 +1,5 @@
import 'dart:developer';
class L {
static final int _maxDepth = 20;
static bool _traceEnabled = false;
@ -6,7 +8,8 @@ class L {
static int _traceDepth = 0;
static int _depthPastMaxDepth = 0;
static void setTraceEnabled(bool enabled) {
static bool get traceEnabled => _traceEnabled;
static set traceEnabled(bool enabled) {
if (_traceEnabled == enabled) {
return;
}
@ -27,9 +30,7 @@ class L {
}
_sections[_traceDepth] = section;
_startTimeNs[_traceDepth] = DateTime.now().microsecondsSinceEpoch;
//TODO(xha): use flutter trace infrastructure
//TraceCompat.beginSection(section);
//print(section);
Timeline.startSync('Lottie::$section');
_traceDepth++;
}
@ -49,8 +50,7 @@ class L {
throw StateError('Unbalanced trace call $section'
'. Expected ${_sections[_traceDepth]}.');
}
//TODO(xha)
//TraceCompat.endSection();
Timeline.finishSync();
return (DateTime.now().microsecondsSinceEpoch - _startTimeNs[_traceDepth]) /
1000;
}

View File

@ -3,6 +3,7 @@ import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import '../lottie.dart';
import 'l.dart';
import 'lottie_builder.dart';
import 'providers/load_image.dart';
@ -235,6 +236,11 @@ class Lottie extends StatefulWidget {
/// and the font family in your assets.
final LottieDelegates delegates;
static bool get traceEnabled => L.traceEnabled;
static set traceEnabled(bool enabled) {
L.traceEnabled = enabled;
}
@override
_LottieState createState() => _LottieState();
}

View File

@ -708,7 +708,7 @@ class JsonUtf8Reader extends JsonReader {
builder ??= StringBuffer();
builder.write(buffer.readUtf8(index));
buffer.readByte(); // '\'
builder.write(readEscapeCharacter());
builder.writeCharCode(readEscapeCharacter());
continue;
}

View File

@ -15,7 +15,7 @@ Future<ui.Image> loadImage(LottieComposition composition,
imageStream.removeListener(listener);
completer.complete(image.image);
}, onError: (e, __) {
}, onError: (dynamic e, __) {
imageStream.removeListener(listener);
composition.addWarning('Failed to load image ${lottieImage.id}: $e');

View File

@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart';
import '../../lottie.dart';
import 'load_image.dart';
abstract class LottieProvider<T> {
abstract class LottieProvider {
LottieProvider({this.imageProviderFactory});
final LottieImageProviderFactory imageProviderFactory;

View File

@ -0,0 +1,101 @@
// Copied from https://github.com/dnfield/flutter_path_drawing
// We don't depend directly on this package to save 2 dependencies
import 'dart:ui';
import 'package:meta/meta.dart';
/// Creates a new path that is drawn from the segments of `source`.
///
/// Dash intervals are controled by the `dashArray` - see [CircularIntervalList]
/// for examples.
///
/// `dashOffset` specifies an initial starting point for the dashing.
///
/// Passing in a null `source` will result in a null result. Passing a `source`
/// that is an empty path will return an empty path.
Path dashPath(
Path source, {
@required CircularIntervalList<double> dashArray,
DashOffset dashOffset,
}) {
assert(dashArray != null);
if (source == null) {
return null;
}
dashOffset = dashOffset ?? const DashOffset.absolute(0.0);
// TODO: Is there some way to determine how much of a path would be visible today?
var dest = Path();
for (final metric in source.computeMetrics()) {
var distance = dashOffset._calculate(metric.length);
var draw = true;
while (distance < metric.length) {
final len = dashArray.next;
if (draw) {
dest.addPath(metric.extractPath(distance, distance + len), Offset.zero);
}
distance += len;
draw = !draw;
}
}
return dest;
}
enum _DashOffsetType { absolute, percentage }
/// Specifies the starting position of a dash array on a path, either as a
/// percentage or absolute value.
///
/// The internal value will be guaranteed to not be null.
class DashOffset {
/// Create a DashOffset that will be measured as a percentage of the length
/// of the segment being dashed.
///
/// `percentage` will be clamped between 0.0 and 1.0; null will be converted
/// to 0.0.
DashOffset.percentage(double percentage)
: _rawVal = percentage.clamp(0.0, 1.0) as double ?? 0.0,
_dashOffsetType = _DashOffsetType.percentage;
/// Create a DashOffset that will be measured in terms of absolute pixels
/// along the length of a [Path] segment.
///
/// `start` will be coerced to 0.0 if null.
const DashOffset.absolute(double start)
: _rawVal = start ?? 0.0,
_dashOffsetType = _DashOffsetType.absolute;
final double _rawVal;
final _DashOffsetType _dashOffsetType;
double _calculate(double length) {
return _dashOffsetType == _DashOffsetType.absolute
? _rawVal
: length * _rawVal;
}
}
/// A circular array of dash offsets and lengths.
///
/// For example, the array `[5, 10]` would result in dashes 5 pixels long
/// followed by blank spaces 10 pixels long. The array `[5, 10, 5]` would
/// result in a 5 pixel dash, a 10 pixel gap, a 5 pixel dash, a 5 pixel gap,
/// a 10 pixel dash, etc.
///
/// Note that this does not quite conform to an [Iterable<T>], because it does
/// not have a moveNext.
class CircularIntervalList<T> {
CircularIntervalList(this._vals);
final List<T> _vals;
int _idx = 0;
T get next {
if (_idx >= _vals.length) {
_idx = 0;
}
return _vals[_idx++];
}
}

View File

@ -272,7 +272,7 @@ class ValueDelegate<T> {
bool isSameProperty(ValueDelegate other) {
if (identical(this, other)) return true;
return other is ValueDelegate<T> &&
const ListEquality().equals(other.keyPath, keyPath) &&
const ListEquality<String>().equals(other.keyPath, keyPath) &&
other.property == property;
}
}

View File

@ -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.0
version: 0.3.2
homepage: https://github.com/xvrh/lottie-flutter
environment:
@ -10,7 +10,7 @@ dependencies:
flutter:
sdk: flutter
archive: ^2.0.0
characters:
characters: ^0.5.0
charcode: ^1.0.0
logging: ^0.11.0
meta: ^1.1.8

View File

@ -69,7 +69,7 @@ class DartProject {
static String _getPackageName(String projectRoot) {
var pubspecContent =
File(p.join(projectRoot, 'pubspec.yaml')).readAsStringSync();
var loadedPubspec = loadYaml(pubspecContent);
var loadedPubspec = loadYaml(pubspecContent) as YamlMap;
return loadedPubspec['name'] as String;
}

View File

@ -6,7 +6,7 @@ void main(List<String> args) {
var pubspec = File('pubspec.yaml');
var content = loadYaml(pubspec.readAsStringSync()) as YamlMap;
var pubspecVersion = content['version'];
var pubspecVersion = content['version'] as String;
var tagVersion = '';
if (args.isNotEmpty) {
tagVersion = args[0].split('/').last;