Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
536 changes: 536 additions & 0 deletions example/lib/interactive_example.dart

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/lottie.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export 'src/api/lottie_api.dart' show LottieApi;
export 'src/composition.dart' show LottieComposition;
export 'src/frame_rate.dart' show FrameRate;
export 'src/lottie.dart' show Lottie;
Expand Down
27 changes: 24 additions & 3 deletions lib/src/animation/content/content_group.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import '../../model/content/shape_group.dart';
import '../../model/key_path.dart';
import '../../model/key_path_element.dart';
import '../../model/layer/base_layer.dart';
import '../../model/lottie_observer.dart';
import '../../utils.dart';
import '../../utils/path_factory.dart';
import '../../value/lottie_value_callback.dart';
Expand All @@ -16,7 +17,8 @@ import 'drawing_content.dart';
import 'greedy_content.dart';
import 'path_content.dart';

class ContentGroup implements DrawingContent, PathContent, KeyPathElement {
class ContentGroup
implements DrawingContent, PathContent, KeyPathElement, LottieObserver {
final Paint _offScreenPaint = Paint();

static List<Content> contentsFromModels(LottieDrawable drawable,
Expand All @@ -42,6 +44,7 @@ class ContentGroup implements DrawingContent, PathContent, KeyPathElement {
}

final Matrix4 _matrix = Matrix4.identity();
Rect _drawBounds = Rect.zero;
final Path _path = PathFactory.create();

@override
Expand Down Expand Up @@ -83,6 +86,21 @@ class ContentGroup implements DrawingContent, PathContent, KeyPathElement {
}
}

@override
void applyToMatrix(final Matrix4 matrix) {
_transformAnimation?.applyToMatrix(matrix);
}

@override
List<LottieObserver> requireMatrixHierarchy() {
return [];
}

@override
bool hitTest(final Offset position) {
return _drawBounds.contains(position);
}

void onValueChanged() {
_lottieDrawable.invalidateSelf();
}
Expand Down Expand Up @@ -165,9 +183,12 @@ class ContentGroup implements DrawingContent, PathContent, KeyPathElement {
hasTwoOrMoreDrawableContent() &&
layerAlpha != 255;
if (isRenderingWithOffScreen) {
var offScreenRect = getBounds(_matrix, applyParents: true);
_drawBounds = getBounds(_matrix, applyParents: true);
_offScreenPaint.setAlpha(layerAlpha);
canvas.saveLayer(offScreenRect, _offScreenPaint);
canvas.saveLayer(_drawBounds, _offScreenPaint);
} else {
var matrix = parentMatrix.clone();
_drawBounds = getBounds(matrix, applyParents: true);
}

var childAlpha = isRenderingWithOffScreen ? 255 : layerAlpha;
Expand Down
24 changes: 20 additions & 4 deletions lib/src/animation/content/fill_content.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import '../../model/content/drop_shadow_effect.dart';
import '../../model/content/shape_fill.dart';
import '../../model/key_path.dart';
import '../../model/layer/base_layer.dart';
import '../../model/lottie_observer.dart';
import '../../utils.dart';
import '../../utils/misc.dart';
import '../../utils/path_factory.dart';
Expand All @@ -20,9 +21,11 @@ import 'drawing_content.dart';
import 'key_path_element_content.dart';
import 'path_content.dart';

class FillContent implements DrawingContent, KeyPathElementContent {
class FillContent
implements DrawingContent, KeyPathElementContent, LottieObserver {
final Path _path = PathFactory.create();
final Paint _paint = Paint();
Rect _drawBounds = Rect.zero;
final BaseLayer layer;
@override
final String? name;
Expand Down Expand Up @@ -65,6 +68,19 @@ class FillContent implements DrawingContent, KeyPathElementContent {
layer.addAnimation(_opacityAnimation);
}

@override
void applyToMatrix(final Matrix4 matrix) {}

@override
List<LottieObserver> requireMatrixHierarchy() {
return [];
}

@override
bool hitTest(final Offset position) {
return _drawBounds.contains(position);
}

void onValueChanged() {
lottieDrawable.invalidateSelf();
}
Expand Down Expand Up @@ -134,10 +150,10 @@ class FillContent implements DrawingContent, KeyPathElementContent {
_path.addPath(_paths[i].getPath(), Offset.zero,
matrix4: parentMatrix.storage);
}
var outBounds = _path.getBounds();
_drawBounds = _path.getBounds();
// Add padding to account for rounding errors.
outBounds = outBounds.inflate(1);
return outBounds;
_drawBounds = _drawBounds.inflate(1);
return _drawBounds;
}

@override
Expand Down
21 changes: 15 additions & 6 deletions lib/src/animation/keyframe/base_keyframe_animation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ abstract class BaseKeyframeAnimation<K extends Object, A extends Object?> {
return _cachedEndProgress;
}

A get rawValue {
return getValue(getCurrentKeyframe(), progress, null);
}

A get value {
A value;

Expand All @@ -116,10 +120,10 @@ abstract class BaseKeyframeAnimation<K extends Object, A extends Object?> {
var xProgress = keyframe.xInterpolator!.transform(linearProgress);
var yProgress = keyframe.yInterpolator!.transform(linearProgress);
value = getValueSplitDimension(
keyframe, linearProgress, xProgress, yProgress);
keyframe, linearProgress, xProgress, yProgress, valueCallback);
} else {
var progress = getInterpolatedCurrentKeyframeProgress();
value = getValue(keyframe, progress);
value = getValue(keyframe, progress, valueCallback);
}

_cachedGetValue = value;
Expand Down Expand Up @@ -148,10 +152,15 @@ abstract class BaseKeyframeAnimation<K extends Object, A extends Object?> {

/// keyframeProgress will be [0, 1] unless the interpolator has overshoot in which case, this
/// should be able to handle values outside of that range.
A getValue(Keyframe<K> keyframe, double keyframeProgress);

A getValueSplitDimension(Keyframe<K> keyframe, double linearKeyframeProgress,
double xKeyframeProgress, double yKeyframeProgress) {
A getValue(Keyframe<K> keyframe, double keyframeProgress,
LottieValueCallback<A>? valueCallback);

A getValueSplitDimension(
Keyframe<K> keyframe,
double linearKeyframeProgress,
double xKeyframeProgress,
double yKeyframeProgress,
LottieValueCallback<A>? valueCallback) {
throw Exception('This animation does not support split dimensions!');
}

Expand Down
6 changes: 4 additions & 2 deletions lib/src/animation/keyframe/color_keyframe_animation.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import 'dart:ui';
import '../../utils/gamma_evaluator.dart';
import '../../value/keyframe.dart';
import '../../value/lottie_value_callback.dart';
import 'keyframe_animation.dart';

class ColorKeyframeAnimation extends KeyframeAnimation<Color> {
ColorKeyframeAnimation(super.keyframes);

@override
Color getValue(Keyframe<Color> keyframe, double keyframeProgress) {
Color getValue(Keyframe<Color> keyframe, double keyframeProgress,
LottieValueCallback<Color>? valueCallback) {
if (keyframe.startValue == null || keyframe.endValue == null) {
throw Exception('Missing values for keyframe.');
}
var startColor = keyframe.startValue;
var endColor = keyframe.endValue;

if (valueCallback != null) {
var value = valueCallback!.getValueInternal(
var value = valueCallback.getValueInternal(
keyframe.startFrame,
keyframe.endFrame,
startColor,
Expand Down
6 changes: 4 additions & 2 deletions lib/src/animation/keyframe/double_keyframe_animation.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import 'dart:ui';
import '../../value/keyframe.dart';
import '../../value/lottie_value_callback.dart';
import 'keyframe_animation.dart';

class DoubleKeyframeAnimation extends KeyframeAnimation<double> {
DoubleKeyframeAnimation(super.keyframes);

@override
double getValue(Keyframe<double> keyframe, double keyframeProgress) {
double getValue(Keyframe<double> keyframe, double keyframeProgress,
LottieValueCallback<double>? valueCallback) {
if (keyframe.startValue == null || keyframe.endValue == null) {
throw Exception('Missing values for keyframe.');
}

if (valueCallback != null) {
var value = valueCallback!.getValueInternal(
var value = valueCallback.getValueInternal(
keyframe.startFrame,
keyframe.endFrame,
keyframe.startValue,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:ui';
import '../../model/content/gradient_color.dart';
import '../../value/keyframe.dart';
import '../../value/lottie_value_callback.dart';
import 'keyframe_animation.dart';

class GradientColorKeyframeAnimation extends KeyframeAnimation<GradientColor> {
Expand All @@ -16,7 +17,9 @@ class GradientColorKeyframeAnimation extends KeyframeAnimation<GradientColor> {

@override
GradientColor getValue(
Keyframe<GradientColor> keyframe, double keyframeProgress) {
Keyframe<GradientColor> keyframe,
double keyframeProgress,
LottieValueCallback<GradientColor>? valueCallback) {
_gradientColor.lerp(
keyframe.startValue!, keyframe.endValue!, keyframeProgress);
return _gradientColor;
Expand Down
6 changes: 4 additions & 2 deletions lib/src/animation/keyframe/integer_keyframe_animation.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import 'dart:ui';
import '../../value/keyframe.dart';
import '../../value/lottie_value_callback.dart';
import 'keyframe_animation.dart';

class IntegerKeyframeAnimation extends KeyframeAnimation<int> {
IntegerKeyframeAnimation(super.keyframes);

@override
int getValue(Keyframe<int> keyframe, double keyframeProgress) {
int getValue(Keyframe<int> keyframe, double keyframeProgress,
LottieValueCallback<int>? valueCallback) {
if (keyframe.startValue == null || keyframe.endValue == null) {
throw Exception('Missing values for keyframe.');
}

if (valueCallback != null) {
var value = valueCallback!.getValueInternal(
var value = valueCallback.getValueInternal(
keyframe.startFrame,
keyframe.endFrame,
keyframe.startValue,
Expand Down
6 changes: 4 additions & 2 deletions lib/src/animation/keyframe/path_keyframe_animation.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:ui';
import '../../value/keyframe.dart';
import '../../value/lottie_value_callback.dart';
import 'keyframe_animation.dart';
import 'path_keyframe.dart';

Expand All @@ -10,15 +11,16 @@ class PathKeyframeAnimation extends KeyframeAnimation<Offset> {
PathKeyframeAnimation(super.keyframes);

@override
Offset getValue(Keyframe<Offset> keyframe, double keyframeProgress) {
Offset getValue(Keyframe<Offset> keyframe, double keyframeProgress,
LottieValueCallback<Offset>? valueCallback) {
var pathKeyframe = keyframe as PathKeyframe;
var path = pathKeyframe.getPath();
if (path == null) {
return keyframe.startValue!;
}

if (valueCallback != null) {
var value = valueCallback!.getValueInternal(
var value = valueCallback.getValueInternal(
pathKeyframe.startFrame,
pathKeyframe.endFrame,
pathKeyframe.startValue,
Expand Down
13 changes: 8 additions & 5 deletions lib/src/animation/keyframe/point_keyframe_animation.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import 'dart:ui';
import '../../value/keyframe.dart';
import '../../value/lottie_value_callback.dart';
import 'keyframe_animation.dart';

class PointKeyframeAnimation extends KeyframeAnimation<Offset> {
PointKeyframeAnimation(super.keyframes);

@override
Offset getValue(Keyframe<Offset> keyframe, double keyframeProgress) {
return getValueSplitDimension(
keyframe, keyframeProgress, keyframeProgress, keyframeProgress);
Offset getValue(Keyframe<Offset> keyframe, double keyframeProgress,
LottieValueCallback<Offset>? valueCallback) {
return getValueSplitDimension(keyframe, keyframeProgress, keyframeProgress,
keyframeProgress, valueCallback);
}

@override
Offset getValueSplitDimension(
Keyframe<Offset> keyframe,
double linearKeyframeProgress,
double xKeyframeProgress,
double yKeyframeProgress) {
double yKeyframeProgress,
LottieValueCallback<Offset>? valueCallback) {
if (keyframe.startValue == null || keyframe.endValue == null) {
throw Exception('Missing values for keyframe.');
}
Expand All @@ -25,7 +28,7 @@ class PointKeyframeAnimation extends KeyframeAnimation<Offset> {
var endPoint = keyframe.endValue!;

if (valueCallback != null) {
var value = valueCallback!.getValueInternal(
var value = valueCallback.getValueInternal(
keyframe.startFrame,
keyframe.endFrame,
startPoint,
Expand Down
4 changes: 3 additions & 1 deletion lib/src/animation/keyframe/shape_keyframe_animation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import '../../model/content/shape_data.dart';
import '../../utils/misc.dart';
import '../../utils/path_factory.dart';
import '../../value/keyframe.dart';
import '../../value/lottie_value_callback.dart';
import '../content/shape_modifier_content.dart';
import 'base_keyframe_animation.dart';

Expand All @@ -14,7 +15,8 @@ class ShapeKeyframeAnimation extends BaseKeyframeAnimation<ShapeData, Path> {
ShapeKeyframeAnimation(super.keyframes);

@override
Path getValue(Keyframe<ShapeData> keyframe, double keyframeProgress) {
Path getValue(Keyframe<ShapeData> keyframe, double keyframeProgress,
LottieValueCallback<Path>? valueCallback) {
var startShapeData = keyframe.startValue!;
var endShapeData = keyframe.endValue!;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:ui';
import '../../value/keyframe.dart';
import '../../value/lottie_value_callback.dart';
import 'base_keyframe_animation.dart';

class SplitDimensionPathKeyframeAnimation
Expand Down Expand Up @@ -30,7 +31,8 @@ class SplitDimensionPathKeyframeAnimation
}

@override
Offset getValue(Keyframe<Offset> keyframe, double keyframeProgress) {
Offset getValue(Keyframe<Offset> keyframe, double keyframeProgress,
LottieValueCallback<Offset>? valueCallback) {
return _point;
}
}
5 changes: 3 additions & 2 deletions lib/src/animation/keyframe/text_keyframe_animation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ class TextKeyframeAnimation extends KeyframeAnimation<DocumentData> {

@override
DocumentData getValue(
Keyframe<DocumentData> keyframe, double keyframeProgress) {
var valueCallback = this.valueCallback;
Keyframe<DocumentData> keyframe,
double keyframeProgress,
LottieValueCallback<DocumentData>? valueCallback) {
if (valueCallback != null) {
return valueCallback.getValueInternal(
keyframe.startFrame,
Expand Down
Loading