Compare commits

..

1 Commits

Author SHA1 Message Date
98c2efe12d Fix path bug (#11) 2020-02-11 12:43:50 +01:00
17 changed files with 34 additions and 43 deletions

View File

@ -1,3 +1,6 @@
## [0.2.1] - 2020-02-11
- Fix a big bug in the path transformation code. A lot more animations look correct now.
## [0.2.0+1] - 2020-02-04 ## [0.2.0+1] - 2020-02-04
- Improve readme - Improve readme
- (internal) Add golden tests - (internal) Add golden tests

View File

@ -8,7 +8,7 @@ if (localPropertiesFile.exists()) {
def flutterRoot = localProperties.getProperty('flutter.sdk') def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) { if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") throw new Exception("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
} }
def flutterVersionCode = localProperties.getProperty('flutter.versionCode') def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
@ -37,8 +37,7 @@ android {
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.github.xvrh.lottie.sample"
applicationId "com.example.example"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 28 targetSdkVersion 28
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()

View File

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.example"> package="com.github.xvrh.lottie.sample">
<!-- Flutter needs it to communicate with the running application <!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->

View File

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.example"> package="com.github.xvrh.lottie.sample">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that <!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method. calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide In most cases you can leave this as-is, but you if you want to provide

View File

@ -1,4 +1,4 @@
package com.example.example package com.github.xvrh.lottie.sample
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity

View File

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.example"> package="com.github.xvrh.lottie.sample">
<!-- Flutter needs it to communicate with the running application <!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->

View File

@ -322,7 +322,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_BUNDLE_IDENTIFIER = com.github.xvrh.lottie.sample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@ -457,7 +457,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_BUNDLE_IDENTIFIER = com.github.xvrh.lottie.sample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -485,7 +485,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_BUNDLE_IDENTIFIER = com.github.xvrh.lottie.sample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;

View File

@ -8,7 +8,7 @@
PRODUCT_NAME = example PRODUCT_NAME = example
// The application's bundle identifier // The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = com.example.example PRODUCT_BUNDLE_IDENTIFIER = com.github.xvrh.lottie.sample
// The copyright displayed in application information // The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2020 com.example. All rights reserved. PRODUCT_COPYRIGHT = Copyright © 2020 com.example. All rights reserved.

View File

@ -182,8 +182,8 @@ abstract class BaseStrokeContent
var currentLength = 0.0; var currentLength = 0.0;
for (var j = pathGroup.paths.length - 1; j >= 0; j--) { for (var j = pathGroup.paths.length - 1; j >= 0; j--) {
_trimPathPath.set(pathGroup.paths[j].getPath()); _trimPathPath
_trimPathPath.transform(parentMatrix.storage); .set(pathGroup.paths[j].getPath().transform(parentMatrix.storage));
var pathMetrics = _trimPathPath.computeMetrics().toList(); var pathMetrics = _trimPathPath.computeMetrics().toList();
var length = pathMetrics.first.length; var length = pathMetrics.first.length;
if (endLength > totalLength && if (endLength > totalLength &&

View File

@ -87,7 +87,7 @@ class MergePathsContent implements PathContent, GreedyContent {
var pathList = content.getPathList(); var pathList = content.getPathList();
for (var j = pathList.length - 1; j >= 0; j--) { for (var j = pathList.length - 1; j >= 0; j--) {
var path = pathList[j].getPath(); var path = pathList[j].getPath();
path.transform(content.getTransformationMatrix().storage); path = path.transform(content.getTransformationMatrix().storage);
_remainderPath.addPath(path, Offset.zero); _remainderPath.addPath(path, Offset.zero);
} }
} else { } else {
@ -100,7 +100,7 @@ class MergePathsContent implements PathContent, GreedyContent {
var pathList = lastContent.getPathList(); var pathList = lastContent.getPathList();
for (var j = 0; j < pathList.length; j++) { for (var j = 0; j < pathList.length; j++) {
var path = pathList[j].getPath(); var path = pathList[j].getPath();
path.transform(lastContent.getTransformationMatrix().storage); path = path.transform(lastContent.getTransformationMatrix().storage);
_firstPath.addPath(path, Offset.zero); _firstPath.addPath(path, Offset.zero);
} }
} else { } else {

View File

@ -52,7 +52,6 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
} }
} }
final ui.Path _path = ui.Path();
final Matrix4 _matrix = Matrix4.identity(); final Matrix4 _matrix = Matrix4.identity();
final Paint _contentPaint = ui.Paint(); final Paint _contentPaint = ui.Paint();
final Paint _dstInPaint = ui.Paint()..blendMode = ui.BlendMode.dstIn; final Paint _dstInPaint = ui.Paint()..blendMode = ui.BlendMode.dstIn;
@ -279,8 +278,7 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
BaseKeyframeAnimation<dynamic, Path> maskAnimation = BaseKeyframeAnimation<dynamic, Path> maskAnimation =
_mask.maskAnimations[i]; _mask.maskAnimations[i];
var maskPath = maskAnimation.value; var maskPath = maskAnimation.value;
_path.set(maskPath); var path = maskPath.transform(matrix.storage);
_path.transform(matrix.storage);
switch (mask.maskMode) { switch (mask.maskMode) {
case MaskMode.maskModeNone: case MaskMode.maskModeNone:
@ -297,7 +295,7 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
return bounds; return bounds;
} }
var maskBounds = _path.getBounds(); var maskBounds = path.getBounds();
// As we iterate through the masks, we want to calculate the union region of the masks. // As we iterate through the masks, we want to calculate the union region of the masks.
// We initialize the rect with the first mask. If we don't call set() on the first call, // We initialize the rect with the first mask. If we don't call set() on the first call,
// the rect will always extend to (0,0). // the rect will always extend to (0,0).
@ -420,11 +418,9 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
BaseKeyframeAnimation<ShapeData, Path> maskAnimation, BaseKeyframeAnimation<ShapeData, Path> maskAnimation,
BaseKeyframeAnimation<int, int> opacityAnimation) { BaseKeyframeAnimation<int, int> opacityAnimation) {
var maskPath = maskAnimation.value; var maskPath = maskAnimation.value;
_path var path = maskPath.transform(matrix.storage);
..set(maskPath)
..transform(matrix.storage);
_contentPaint.setAlpha((opacityAnimation.value * 2.55).round()); _contentPaint.setAlpha((opacityAnimation.value * 2.55).round());
canvas.drawPath(_path, _contentPaint); canvas.drawPath(path, _contentPaint);
} }
void _applyInvertedAddMask( void _applyInvertedAddMask(
@ -437,11 +433,9 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
canvas.saveLayer(bounds, _contentPaint); canvas.saveLayer(bounds, _contentPaint);
canvas.drawRect(bounds, _contentPaint); canvas.drawRect(bounds, _contentPaint);
var maskPath = maskAnimation.value; var maskPath = maskAnimation.value;
_path var path = maskPath.transform(matrix.storage);
..set(maskPath)
..transform(matrix.storage);
_contentPaint.setAlpha((opacityAnimation.value * 2.55).round()); _contentPaint.setAlpha((opacityAnimation.value * 2.55).round());
canvas.drawPath(_path, _dstOutPaint); canvas.drawPath(path, _dstOutPaint);
canvas.restore(); canvas.restore();
} }
@ -452,10 +446,8 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
BaseKeyframeAnimation<ShapeData, Path> maskAnimation, BaseKeyframeAnimation<ShapeData, Path> maskAnimation,
BaseKeyframeAnimation<int, int> opacityAnimation) { BaseKeyframeAnimation<int, int> opacityAnimation) {
var maskPath = maskAnimation.value; var maskPath = maskAnimation.value;
_path var path = maskPath.transform(matrix.storage);
..set(maskPath) canvas.drawPath(path, _dstOutPaint);
..transform(matrix.storage);
canvas.drawPath(_path, _dstOutPaint);
} }
void _applyInvertedSubtractMask( void _applyInvertedSubtractMask(
@ -470,9 +462,8 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
_dstOutPaint.setAlpha((opacityAnimation.value * 2.55).round()); _dstOutPaint.setAlpha((opacityAnimation.value * 2.55).round());
var maskPath = maskAnimation.value; var maskPath = maskAnimation.value;
_path.set(maskPath); var path = maskPath.transform(matrix.storage);
_path.transform(matrix.storage); canvas.drawPath(path, _dstOutPaint);
canvas.drawPath(_path, _dstOutPaint);
canvas.restore(); canvas.restore();
} }
@ -485,10 +476,9 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
BaseKeyframeAnimation<int, int> opacityAnimation) { BaseKeyframeAnimation<int, int> opacityAnimation) {
canvas.saveLayer(bounds, _dstInPaint); canvas.saveLayer(bounds, _dstInPaint);
var maskPath = maskAnimation.value; var maskPath = maskAnimation.value;
_path.set(maskPath); var path = maskPath.transform(matrix.storage);
_path.transform(matrix.storage);
_contentPaint.setAlpha((opacityAnimation.value * 2.55).round()); _contentPaint.setAlpha((opacityAnimation.value * 2.55).round());
canvas.drawPath(_path, _contentPaint); canvas.drawPath(path, _contentPaint);
canvas.restore(); canvas.restore();
} }
@ -503,9 +493,8 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
canvas.drawRect(bounds, _contentPaint); canvas.drawRect(bounds, _contentPaint);
_dstOutPaint.setAlpha((opacityAnimation.value * 2.55).round()); _dstOutPaint.setAlpha((opacityAnimation.value * 2.55).round());
var maskPath = maskAnimation.value; var maskPath = maskAnimation.value;
_path.set(maskPath); var path = maskPath.transform(matrix.storage);
_path.transform(matrix.storage); canvas.drawPath(path, _dstOutPaint);
canvas.drawPath(_path, _dstOutPaint);
canvas.restore(); canvas.restore();
} }

View File

@ -348,7 +348,7 @@ class TextLayer extends BaseLayer {
_matrix.translate( _matrix.translate(
0.0, -documentData.baselineShift * window.devicePixelRatio); 0.0, -documentData.baselineShift * window.devicePixelRatio);
_matrix.scale(fontScale, fontScale); _matrix.scale(fontScale, fontScale);
path.transform(_matrix.storage); path = path.transform(_matrix.storage);
if (documentData.strokeOverFill) { if (documentData.strokeOverFill) {
_drawGlyph(path, _fillPaint, canvas); _drawGlyph(path, _fillPaint, canvas);
_drawGlyph(path, _strokePaint, canvas); _drawGlyph(path, _strokePaint, canvas);

View File

@ -67,7 +67,7 @@ class MiscUtils {
} }
static int floorMod(double x, double y) { static int floorMod(double x, double y) {
return _floorDiv(x.round(), y.round()); return x.toInt() - y.toInt() * _floorDiv(x.toInt(), y.toInt());
} }
static int _floorDiv(int x, int y) { static int _floorDiv(int x, int y) {

View File

@ -1,6 +1,6 @@
name: lottie name: lottie
description: Render After Effects animations natively on Flutter. This package is a pure Dart implementation of a Lottie player. description: Render After Effects animations natively on Flutter. This package is a pure Dart implementation of a Lottie player.
version: 0.2.0+1 version: 0.2.1
homepage: https://github.com/xvrh/lottie-flutter homepage: https://github.com/xvrh/lottie-flutter
environment: environment:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 133 KiB