Expose LottieDelegates to modify animation properties at runtime (#23)

This commit is contained in:
Xavier H
2020-03-02 22:11:38 +01:00
committed by GitHub
parent 4ae257eaab
commit e89c3c4914
93 changed files with 1372 additions and 343 deletions

331
lib/src/value_delegate.dart Normal file
View File

@ -0,0 +1,331 @@
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'lottie_drawable.dart';
import 'lottie_property.dart';
import 'model/key_path.dart';
import 'value/lottie_frame_info.dart';
import 'value/lottie_relative_double_value_callback.dart';
import 'value/lottie_relative_integer_value_callback.dart';
import 'value/lottie_relative_point_value_callback.dart';
import 'value/lottie_value_callback.dart';
class ValueDelegate<T> {
final List<String> keyPath;
final T property;
final T value;
final T Function(LottieFrameInfo<T>) callback;
ValueDelegate._(this.keyPath, this.property, this.value, this.callback)
: assert(value == null || callback == null,
"Value and callback can't be both specified.");
static ValueDelegate<Offset> _offset(
List<String> keyPath,
Offset property,
Offset value,
Offset Function(LottieFrameInfo<Offset>) callback,
Offset relative) {
if (relative != null) {
assert(callback == null);
callback = relativeOffsetValueCallback(relative);
}
return ValueDelegate<Offset>._(keyPath, property, value, callback);
}
static ValueDelegate<double> _double(
List<String> keyPath,
double property,
double value,
double Function(LottieFrameInfo<double>) callback,
double relative) {
if (relative != null) {
assert(callback == null);
callback = relativeDoubleValueCallback(relative);
}
return ValueDelegate<double>._(keyPath, property, value, callback);
}
static ValueDelegate<int> _int(List<String> keyPath, int property, int value,
int Function(LottieFrameInfo<int>) callback, int relative) {
if (relative != null) {
assert(callback == null);
callback = relativeIntegerValueCallback(relative);
}
return ValueDelegate<int>._(keyPath, property, value, callback);
}
static ValueDelegate<Color> color(List<String> keyPath,
{Color value, Color Function(LottieFrameInfo<Color>) callback}) =>
ValueDelegate._(keyPath, LottieProperty.color, value, callback);
static ValueDelegate<Color> strokeColor(List<String> keyPath,
{Color value, Color Function(LottieFrameInfo<Color>) callback}) =>
ValueDelegate._(keyPath, LottieProperty.strokeColor, value, callback);
/// Opacity value are 0-100 to match after effects
static ValueDelegate<int> transformOpacity(List<String> keyPath,
{int value,
int Function(LottieFrameInfo<int>) callback,
int relative}) =>
_int(keyPath, LottieProperty.transformOpacity, value, callback, relative);
/// Opacity value are 0-100 to match after effects
static ValueDelegate<int> opacity(List<String> keyPath,
{int value,
int Function(LottieFrameInfo<int>) callback,
int relative}) =>
_int(keyPath, LottieProperty.opacity, value, callback, relative);
static ValueDelegate<Offset> transformAnchorPoint(
List<String> keyPath, {
Offset value,
Offset Function(LottieFrameInfo<Offset>) callback,
Offset relative,
}) {
return _offset(keyPath, LottieProperty.transformAnchorPoint, value,
callback, relative);
}
static ValueDelegate<Offset> transformPosition(
List<String> keyPath, {
Offset value,
Offset Function(LottieFrameInfo<Offset>) callback,
Offset relative,
}) =>
_offset(
keyPath, LottieProperty.transformPosition, value, callback, relative);
static ValueDelegate<Offset> ellipseSize(
List<String> keyPath, {
Offset value,
Offset Function(LottieFrameInfo<Offset>) callback,
Offset relative,
}) =>
_offset(keyPath, LottieProperty.ellipseSize, value, callback, relative);
static ValueDelegate<Offset> rectangleSize(
List<String> keyPath, {
Offset value,
Offset Function(LottieFrameInfo<Offset>) callback,
Offset relative,
}) =>
_offset(keyPath, LottieProperty.rectangleSize, value, callback, relative);
static ValueDelegate<double> cornerRadius(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.cornerRadius, value, callback, relative);
static ValueDelegate<Offset> position(
List<String> keyPath, {
Offset value,
Offset Function(LottieFrameInfo<Offset>) callback,
Offset relative,
}) =>
_offset(keyPath, LottieProperty.position, value, callback, relative);
static ValueDelegate<Offset> transformScale(
List<String> keyPath, {
Offset value,
Offset Function(LottieFrameInfo<Offset>) callback,
Offset relative,
}) =>
_offset(
keyPath, LottieProperty.transformScale, value, callback, relative);
/// In degrees
static ValueDelegate<double> transformRotation(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(
keyPath, LottieProperty.transformRotation, value, callback, relative);
static ValueDelegate<double> transformSkew(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.transformSkew, value, callback, relative);
static ValueDelegate<double> transformSkewAngle(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.transformSkewAngle, value, callback,
relative);
static ValueDelegate<double> strokeWidth(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.strokeWidth, value, callback, relative);
static ValueDelegate<double> textTracking(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.textTracking, value, callback, relative);
static ValueDelegate<double> repeaterCopies(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(
keyPath, LottieProperty.repeaterCopies, value, callback, relative);
static ValueDelegate<double> repeaterOffset(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(
keyPath, LottieProperty.repeaterOffset, value, callback, relative);
static ValueDelegate<double> polystarPoints(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(
keyPath, LottieProperty.polystarPoints, value, callback, relative);
/// In degrees
static ValueDelegate<double> polystarRotation(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(
keyPath, LottieProperty.polystarRotation, value, callback, relative);
static ValueDelegate<double> polystarInnerRadius(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.polystarInnerRadius, value, callback,
relative);
static ValueDelegate<double> polystarOuterRadius(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.polystarOuterRadius, value, callback,
relative);
static ValueDelegate<double> polystarInnerRoundedness(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.polystarInnerRoundedness, value, callback,
relative);
static ValueDelegate<double> polystarOuterRoundedness(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.polystarOuterRoundedness, value, callback,
relative);
/// Opacity value are 0-100 to match after effects
static ValueDelegate<double> transformStartOpacity(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.transformStartOpacity, value, callback,
relative);
/// Opacity value are 0-100 to match after effects
static ValueDelegate<double> transformEndOpacity(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.transformEndOpacity, value, callback,
relative);
/// The time value in seconds
static ValueDelegate<double> timeRemap(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.timeRemap, value, callback, relative);
static ValueDelegate<double> textSize(List<String> keyPath,
{double value,
double Function(LottieFrameInfo<double>) callback,
double relative}) =>
_double(keyPath, LottieProperty.textSize, value, callback, relative);
static ValueDelegate<ColorFilter> colorFilter(List<String> keyPath,
{ColorFilter value,
ColorFilter Function(LottieFrameInfo<ColorFilter>) callback}) =>
ValueDelegate._(keyPath, LottieProperty.colorFilter, value, callback);
static ValueDelegate<List<Color>> gradientColor(List<String> keyPath,
{List<Color> value,
List<Color> Function(LottieFrameInfo<List<Color>>) callback}) =>
ValueDelegate._(keyPath, LottieProperty.gradientColor, value, callback);
ResolvedValueDelegate<T> _resolved;
ResolvedValueDelegate _resolve(List<KeyPath> resolvedPaths) {
_resolved = ResolvedValueDelegate<T>(this, resolvedPaths);
return _resolved;
}
bool isSameProperty(ValueDelegate other) {
if (identical(this, other)) return true;
return other is ValueDelegate<T> &&
const ListEquality().equals(other.keyPath, keyPath) &&
other.property == property;
}
}
ResolvedValueDelegate internalResolved(ValueDelegate valueDelegate) {
return valueDelegate._resolved;
}
ResolvedValueDelegate internalResolve(
ValueDelegate delegate, List<KeyPath> resolvedPaths) {
return delegate._resolve(resolvedPaths);
}
class ResolvedValueDelegate<T> {
final ValueDelegate<T> valueDelegate;
final List<KeyPath> keyPaths;
final LottieValueCallback<T> valueCallback;
ResolvedValueDelegate(this.valueDelegate, this.keyPaths)
: valueCallback = LottieValueCallback(valueDelegate.value)
..callback = valueDelegate.callback;
T get property => valueDelegate.property;
void updateDelegate(ValueDelegate<T> delegate) {
valueCallback
..setValue(delegate.value)
..callback = delegate.callback;
}
void clear() {
valueCallback
..setValue(null)
..callback = null;
}
/// Add a property callback for the specified {@link KeyPath}. This {@link KeyPath} can resolve
/// to multiple contents. In that case, the callbacks's value will apply to all of them.
/// <p>
/// Internally, this will check if the {@link KeyPath} has already been resolved with
/// {@link #resolveKeyPath(KeyPath)} and will resolve it if it hasn't.
void addValueCallback(LottieDrawable drawable) {
for (var keyPath in keyPaths) {
keyPath.resolvedElement.addValueCallback<T>(property, valueCallback);
}
if (keyPaths.isNotEmpty) {
drawable.invalidateSelf();
if (property == LottieProperty.timeRemap) {
// Time remapping values are read in setProgress. In order for the new value
// to apply, we have to re-set the progress with the current progress so that the
// time remapping can be reapplied.
drawable.setProgress(drawable.progress);
}
}
}
}