mirror of
https://github.com/rive-app/rive-flutter.git
synced 2025-06-28 02:37:16 +08:00
Adding trim path support.
This commit is contained in:
@ -1,3 +1,7 @@
|
||||
## [0.5.2] - 2020-08-28 18:24:45
|
||||
|
||||
- Adding trim paths.
|
||||
|
||||
## [0.5.1] - 2020-08-26 18:09:13
|
||||
|
||||
- Bumping version number to match the runtime file version (5.1).
|
||||
|
@ -7,7 +7,7 @@
|
||||
## Add to pubspec.yaml
|
||||
```yaml
|
||||
dependencies:
|
||||
rive: ^0.0.1+3
|
||||
rive: ^0.5.2
|
||||
```
|
||||
|
||||
## Example
|
||||
|
@ -94,7 +94,7 @@ packages:
|
||||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.5.1"
|
||||
version: "0.5.2"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -38,6 +38,7 @@ import 'package:rive/src/generated/shapes/paint/radial_gradient_base.dart';
|
||||
import 'package:rive/src/generated/shapes/paint/shape_paint_base.dart';
|
||||
import 'package:rive/src/generated/shapes/paint/solid_color_base.dart';
|
||||
import 'package:rive/src/generated/shapes/paint/stroke_base.dart';
|
||||
import 'package:rive/src/generated/shapes/paint/trim_path_base.dart';
|
||||
import 'package:rive/src/generated/shapes/parametric_path_base.dart';
|
||||
import 'package:rive/src/generated/shapes/path_composer_base.dart';
|
||||
import 'package:rive/src/generated/shapes/path_vertex_base.dart';
|
||||
@ -76,6 +77,7 @@ import 'package:rive/src/rive_core/shapes/paint/linear_gradient.dart';
|
||||
import 'package:rive/src/rive_core/shapes/paint/radial_gradient.dart';
|
||||
import 'package:rive/src/rive_core/shapes/paint/solid_color.dart';
|
||||
import 'package:rive/src/rive_core/shapes/paint/stroke.dart';
|
||||
import 'package:rive/src/rive_core/shapes/paint/trim_path.dart';
|
||||
import 'package:rive/src/rive_core/shapes/path_composer.dart';
|
||||
import 'package:rive/src/rive_core/shapes/points_path.dart';
|
||||
import 'package:rive/src/rive_core/shapes/rectangle.dart';
|
||||
@ -115,6 +117,8 @@ class RiveCoreContext {
|
||||
return SolidColor();
|
||||
case GradientStopBase.typeKey:
|
||||
return GradientStop();
|
||||
case TrimPathBase.typeKey:
|
||||
return TrimPath();
|
||||
case FillBase.typeKey:
|
||||
return Fill();
|
||||
case NodeBase.typeKey:
|
||||
@ -348,6 +352,26 @@ class RiveCoreContext {
|
||||
object.position = value;
|
||||
}
|
||||
break;
|
||||
case TrimPathBase.startPropertyKey:
|
||||
if (object is TrimPathBase && value is double) {
|
||||
object.start = value;
|
||||
}
|
||||
break;
|
||||
case TrimPathBase.endPropertyKey:
|
||||
if (object is TrimPathBase && value is double) {
|
||||
object.end = value;
|
||||
}
|
||||
break;
|
||||
case TrimPathBase.offsetPropertyKey:
|
||||
if (object is TrimPathBase && value is double) {
|
||||
object.offset = value;
|
||||
}
|
||||
break;
|
||||
case TrimPathBase.modeValuePropertyKey:
|
||||
if (object is TrimPathBase && value is int) {
|
||||
object.modeValue = value;
|
||||
}
|
||||
break;
|
||||
case FillBase.fillRulePropertyKey:
|
||||
if (object is FillBase && value is int) {
|
||||
object.fillRule = value;
|
||||
@ -653,6 +677,7 @@ class RiveCoreContext {
|
||||
case ComponentBase.parentIdPropertyKey:
|
||||
case StrokeBase.capPropertyKey:
|
||||
case StrokeBase.joinPropertyKey:
|
||||
case TrimPathBase.modeValuePropertyKey:
|
||||
case FillBase.fillRulePropertyKey:
|
||||
case DrawableBase.drawOrderPropertyKey:
|
||||
case DrawableBase.blendModeValuePropertyKey:
|
||||
@ -682,6 +707,9 @@ class RiveCoreContext {
|
||||
case LinearGradientBase.opacityPropertyKey:
|
||||
case StrokeBase.thicknessPropertyKey:
|
||||
case GradientStopBase.positionPropertyKey:
|
||||
case TrimPathBase.startPropertyKey:
|
||||
case TrimPathBase.endPropertyKey:
|
||||
case TrimPathBase.offsetPropertyKey:
|
||||
case TransformComponentBase.rotationPropertyKey:
|
||||
case TransformComponentBase.scaleXPropertyKey:
|
||||
case TransformComponentBase.scaleYPropertyKey:
|
||||
@ -772,6 +800,8 @@ class RiveCoreContext {
|
||||
return (object as StrokeBase).cap;
|
||||
case StrokeBase.joinPropertyKey:
|
||||
return (object as StrokeBase).join;
|
||||
case TrimPathBase.modeValuePropertyKey:
|
||||
return (object as TrimPathBase).modeValue;
|
||||
case FillBase.fillRulePropertyKey:
|
||||
return (object as FillBase).fillRule;
|
||||
case DrawableBase.drawOrderPropertyKey:
|
||||
@ -838,6 +868,12 @@ class RiveCoreContext {
|
||||
return (object as StrokeBase).thickness;
|
||||
case GradientStopBase.positionPropertyKey:
|
||||
return (object as GradientStopBase).position;
|
||||
case TrimPathBase.startPropertyKey:
|
||||
return (object as TrimPathBase).start;
|
||||
case TrimPathBase.endPropertyKey:
|
||||
return (object as TrimPathBase).end;
|
||||
case TrimPathBase.offsetPropertyKey:
|
||||
return (object as TrimPathBase).offset;
|
||||
case TransformComponentBase.rotationPropertyKey:
|
||||
return (object as TransformComponentBase).rotation;
|
||||
case TransformComponentBase.scaleXPropertyKey:
|
||||
@ -1001,6 +1037,9 @@ class RiveCoreContext {
|
||||
case StrokeBase.joinPropertyKey:
|
||||
(object as StrokeBase).join = value;
|
||||
break;
|
||||
case TrimPathBase.modeValuePropertyKey:
|
||||
(object as TrimPathBase).modeValue = value;
|
||||
break;
|
||||
case FillBase.fillRulePropertyKey:
|
||||
(object as FillBase).fillRule = value;
|
||||
break;
|
||||
@ -1092,6 +1131,15 @@ class RiveCoreContext {
|
||||
case GradientStopBase.positionPropertyKey:
|
||||
(object as GradientStopBase).position = value;
|
||||
break;
|
||||
case TrimPathBase.startPropertyKey:
|
||||
(object as TrimPathBase).start = value;
|
||||
break;
|
||||
case TrimPathBase.endPropertyKey:
|
||||
(object as TrimPathBase).end = value;
|
||||
break;
|
||||
case TrimPathBase.offsetPropertyKey:
|
||||
(object as TrimPathBase).offset = value;
|
||||
break;
|
||||
case TransformComponentBase.rotationPropertyKey:
|
||||
(object as TransformComponentBase).rotation = value;
|
||||
break;
|
||||
|
90
lib/src/generated/shapes/paint/trim_path_base.dart
Normal file
90
lib/src/generated/shapes/paint/trim_path_base.dart
Normal file
@ -0,0 +1,90 @@
|
||||
/// Core automatically generated
|
||||
/// lib/src/generated/shapes/paint/trim_path_base.dart.
|
||||
/// Do not modify manually.
|
||||
|
||||
import 'package:rive/src/generated/component_base.dart';
|
||||
import 'package:rive/src/rive_core/component.dart';
|
||||
|
||||
abstract class TrimPathBase extends Component {
|
||||
static const int typeKey = 47;
|
||||
@override
|
||||
int get coreType => TrimPathBase.typeKey;
|
||||
@override
|
||||
Set<int> get coreTypes => {TrimPathBase.typeKey, ComponentBase.typeKey};
|
||||
|
||||
/// --------------------------------------------------------------------------
|
||||
/// Start field with key 114.
|
||||
double _start = 0;
|
||||
static const int startPropertyKey = 114;
|
||||
double get start => _start;
|
||||
|
||||
/// Change the [_start] field value.
|
||||
/// [startChanged] will be invoked only if the field's value has changed.
|
||||
set start(double value) {
|
||||
if (_start == value) {
|
||||
return;
|
||||
}
|
||||
double from = _start;
|
||||
_start = value;
|
||||
startChanged(from, value);
|
||||
}
|
||||
|
||||
void startChanged(double from, double to);
|
||||
|
||||
/// --------------------------------------------------------------------------
|
||||
/// End field with key 115.
|
||||
double _end = 0;
|
||||
static const int endPropertyKey = 115;
|
||||
double get end => _end;
|
||||
|
||||
/// Change the [_end] field value.
|
||||
/// [endChanged] will be invoked only if the field's value has changed.
|
||||
set end(double value) {
|
||||
if (_end == value) {
|
||||
return;
|
||||
}
|
||||
double from = _end;
|
||||
_end = value;
|
||||
endChanged(from, value);
|
||||
}
|
||||
|
||||
void endChanged(double from, double to);
|
||||
|
||||
/// --------------------------------------------------------------------------
|
||||
/// Offset field with key 116.
|
||||
double _offset = 0;
|
||||
static const int offsetPropertyKey = 116;
|
||||
double get offset => _offset;
|
||||
|
||||
/// Change the [_offset] field value.
|
||||
/// [offsetChanged] will be invoked only if the field's value has changed.
|
||||
set offset(double value) {
|
||||
if (_offset == value) {
|
||||
return;
|
||||
}
|
||||
double from = _offset;
|
||||
_offset = value;
|
||||
offsetChanged(from, value);
|
||||
}
|
||||
|
||||
void offsetChanged(double from, double to);
|
||||
|
||||
/// --------------------------------------------------------------------------
|
||||
/// ModeValue field with key 117.
|
||||
int _modeValue = 0;
|
||||
static const int modeValuePropertyKey = 117;
|
||||
int get modeValue => _modeValue;
|
||||
|
||||
/// Change the [_modeValue] field value.
|
||||
/// [modeValueChanged] will be invoked only if the field's value has changed.
|
||||
set modeValue(int value) {
|
||||
if (_modeValue == value) {
|
||||
return;
|
||||
}
|
||||
int from = _modeValue;
|
||||
_modeValue = value;
|
||||
modeValueChanged(from, value);
|
||||
}
|
||||
|
||||
void modeValueChanged(int from, int to);
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
|
||||
abstract class Interpolator {
|
||||
int get id;
|
||||
double transform(double value);
|
||||
|
@ -82,6 +82,7 @@ class Artboard extends ArtboardBase with ShapePaintContainer {
|
||||
@override
|
||||
void heightChanged(double from, double to) {
|
||||
addDirt(ComponentDirt.worldTransform);
|
||||
invalidateStrokeEffects();
|
||||
}
|
||||
|
||||
void onComponentDirty(Component component) {
|
||||
@ -122,6 +123,7 @@ class Artboard extends ArtboardBase with ShapePaintContainer {
|
||||
@override
|
||||
void widthChanged(double from, double to) {
|
||||
addDirt(ComponentDirt.worldTransform);
|
||||
invalidateStrokeEffects();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -3,7 +3,6 @@ import 'package:rive/src/rive_core/bones/skinnable.dart';
|
||||
import 'package:rive/src/rive_core/bones/tendon.dart';
|
||||
import 'package:rive/src/rive_core/component.dart';
|
||||
import 'package:rive/src/rive_core/math/mat2d.dart';
|
||||
import 'package:rive/src/rive_core/math/transform_components.dart';
|
||||
import 'package:rive/src/rive_core/shapes/path_vertex.dart';
|
||||
import 'package:rive/src/generated/bones/skin_base.dart';
|
||||
export 'package:rive/src/generated/bones/skin_base.dart';
|
||||
@ -35,8 +34,6 @@ class Skin extends SkinBase {
|
||||
for (final tendon in _tendons) {
|
||||
var boneWorld = tendon.bone.worldTransform;
|
||||
var wt = Mat2D.multiply(temp, boneWorld, tendon.inverseBind);
|
||||
var tc = TransformComponents();
|
||||
Mat2D.decompose(boneWorld, tc);
|
||||
_boneTransforms[bidx++] = wt[0];
|
||||
_boneTransforms[bidx++] = wt[1];
|
||||
_boneTransforms[bidx++] = wt[2];
|
||||
|
@ -9,4 +9,5 @@ class ComponentDirt {
|
||||
static const int paint = 1 << 7;
|
||||
static const int stops = 1 << 8;
|
||||
static const int clip = 1 << 9;
|
||||
static const int blendMode = 1 << 10;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import 'exceptions/rive_format_error_exception.dart';
|
||||
|
||||
class RuntimeHeader {
|
||||
static const int majorVersion = 5;
|
||||
static const int minorVersion = 1;
|
||||
static const int minorVersion = 2;
|
||||
static const String fingerprint = 'RIVE';
|
||||
final int ownerId;
|
||||
final int fileId;
|
||||
|
@ -1,11 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rive/src/rive_core/component_dirt.dart';
|
||||
import 'package:rive/src/rive_core/shapes/paint/stroke_effect.dart';
|
||||
import 'package:rive/src/rive_core/shapes/shape.dart';
|
||||
import 'package:rive/src/rive_core/shapes/shape_paint_container.dart';
|
||||
import 'package:rive/src/generated/shapes/paint/stroke_base.dart';
|
||||
export 'package:rive/src/generated/shapes/paint/stroke_base.dart';
|
||||
|
||||
class Stroke extends StrokeBase {
|
||||
StrokeEffect _effect;
|
||||
StrokeEffect get effect => _effect;
|
||||
// ignore: use_setters_to_change_properties
|
||||
void addStrokeEffect(StrokeEffect effect) {
|
||||
_effect = effect;
|
||||
}
|
||||
|
||||
void removeStrokeEffect(StrokeEffect effect) {
|
||||
if (effect == _effect) {
|
||||
_effect = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Paint makePaint() => Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
@ -52,11 +66,15 @@ class Stroke extends StrokeBase {
|
||||
}
|
||||
}
|
||||
|
||||
void invalidateEffects() {
|
||||
_effect?.invalidateEffect();
|
||||
}
|
||||
|
||||
@override
|
||||
void draw(Canvas canvas, Path path) {
|
||||
if (!isVisible) {
|
||||
return;
|
||||
}
|
||||
canvas.drawPath(path, paint);
|
||||
canvas.drawPath(_effect?.effectPath(path) ?? path, paint);
|
||||
}
|
||||
}
|
||||
|
6
lib/src/rive_core/shapes/paint/stroke_effect.dart
Normal file
6
lib/src/rive_core/shapes/paint/stroke_effect.dart
Normal file
@ -0,0 +1,6 @@
|
||||
import 'dart:ui';
|
||||
|
||||
abstract class StrokeEffect {
|
||||
Path effectPath(Path source);
|
||||
void invalidateEffect();
|
||||
}
|
82
lib/src/rive_core/shapes/paint/trim_path.dart
Normal file
82
lib/src/rive_core/shapes/paint/trim_path.dart
Normal file
@ -0,0 +1,82 @@
|
||||
import 'dart:ui';
|
||||
import 'package:rive/src/rive_core/component_dirt.dart';
|
||||
import 'package:rive/src/rive_core/shapes/paint/stroke.dart';
|
||||
import 'package:rive/src/rive_core/shapes/paint/stroke_effect.dart';
|
||||
import 'package:rive/src/rive_core/shapes/paint/trim_path_drawing.dart';
|
||||
import 'package:rive/src/generated/shapes/paint/trim_path_base.dart';
|
||||
export 'package:rive/src/generated/shapes/paint/trim_path_base.dart';
|
||||
|
||||
enum TrimPathMode { none, sequential, synchronized }
|
||||
|
||||
class TrimPath extends TrimPathBase implements StrokeEffect {
|
||||
final Path _trimmedPath = Path();
|
||||
Path _renderPath;
|
||||
@override
|
||||
Path effectPath(Path source) {
|
||||
if (_renderPath != null) {
|
||||
return _renderPath;
|
||||
}
|
||||
_trimmedPath.reset();
|
||||
var isSequential = mode == TrimPathMode.sequential;
|
||||
double renderStart = start.clamp(0, 1).toDouble();
|
||||
double renderEnd = end.clamp(0, 1).toDouble();
|
||||
bool inverted = renderStart > renderEnd;
|
||||
if ((renderStart - renderEnd).abs() != 1.0) {
|
||||
renderStart = (renderStart + offset) % 1.0;
|
||||
renderEnd = (renderEnd + offset) % 1.0;
|
||||
if (renderStart < 0) {
|
||||
renderStart += 1.0;
|
||||
}
|
||||
if (renderEnd < 0) {
|
||||
renderEnd += 1.0;
|
||||
}
|
||||
if (inverted) {
|
||||
final double swap = renderEnd;
|
||||
renderEnd = renderStart;
|
||||
renderStart = swap;
|
||||
}
|
||||
if (renderEnd >= renderStart) {
|
||||
updateTrimPath(
|
||||
source, _trimmedPath, renderStart, renderEnd, false, isSequential);
|
||||
} else {
|
||||
updateTrimPath(
|
||||
source, _trimmedPath, renderEnd, renderStart, true, isSequential);
|
||||
}
|
||||
} else {
|
||||
return _renderPath = source;
|
||||
}
|
||||
return _renderPath = _trimmedPath;
|
||||
}
|
||||
|
||||
Stroke get stroke => parent as Stroke;
|
||||
TrimPathMode get mode => TrimPathMode.values[modeValue];
|
||||
set mode(TrimPathMode value) => modeValue = value.index;
|
||||
@override
|
||||
void invalidateEffect() {
|
||||
_renderPath = null;
|
||||
stroke?.shapePaintContainer?.addDirt(ComponentDirt.paint);
|
||||
}
|
||||
|
||||
@override
|
||||
void endChanged(double from, double to) => invalidateEffect();
|
||||
@override
|
||||
void modeValueChanged(int from, int to) => invalidateEffect();
|
||||
@override
|
||||
void offsetChanged(double from, double to) => invalidateEffect();
|
||||
@override
|
||||
void startChanged(double from, double to) => invalidateEffect();
|
||||
@override
|
||||
void update(int dirt) {}
|
||||
@override
|
||||
void onAdded() {
|
||||
super.onAdded();
|
||||
stroke?.addStrokeEffect(this);
|
||||
_renderPath = null;
|
||||
}
|
||||
|
||||
@override
|
||||
void onRemoved() {
|
||||
stroke?.removeStrokeEffect(this);
|
||||
super.onRemoved();
|
||||
}
|
||||
}
|
94
lib/src/rive_core/shapes/paint/trim_path_drawing.dart
Normal file
94
lib/src/rive_core/shapes/paint/trim_path_drawing.dart
Normal file
@ -0,0 +1,94 @@
|
||||
import 'dart:ui';
|
||||
|
||||
double _appendPathSegmentSequential(Iterator<PathMetric> metricsIterator,
|
||||
Path to, double offset, double start, double stop) {
|
||||
double nextOffset = offset;
|
||||
do {
|
||||
PathMetric metric = metricsIterator.current;
|
||||
nextOffset = offset + metric.length;
|
||||
if (start < nextOffset) {
|
||||
Path extracted = metric.extractPath(start - offset, stop - offset);
|
||||
if (extracted != null) {
|
||||
to.addPath(extracted, Offset.zero);
|
||||
}
|
||||
if (stop < nextOffset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// ignore: parameter_assignments
|
||||
offset = nextOffset;
|
||||
} while (metricsIterator.moveNext());
|
||||
return offset;
|
||||
}
|
||||
|
||||
void _appendPathSegmentSync(
|
||||
PathMetric metric, Path to, double offset, double start, double stop) {
|
||||
double nextOffset = offset + metric.length;
|
||||
if (start < nextOffset) {
|
||||
Path extracted = metric.extractPath(start - offset, stop - offset);
|
||||
if (extracted != null) {
|
||||
to.addPath(extracted, Offset.zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _trimPathSequential(
|
||||
Path path, Path result, double startT, double stopT, bool complement) {
|
||||
PathMetrics metrics = path.computeMetrics();
|
||||
double totalLength = 0.0;
|
||||
for (final PathMetric metric in metrics) {
|
||||
totalLength += metric.length;
|
||||
}
|
||||
metrics = path.computeMetrics();
|
||||
double trimStart = totalLength * startT;
|
||||
double trimStop = totalLength * stopT;
|
||||
double offset = 0.0;
|
||||
Iterator<PathMetric> metricsIterator = metrics.iterator;
|
||||
metricsIterator.moveNext();
|
||||
if (complement) {
|
||||
if (trimStart > 0.0) {
|
||||
offset = _appendPathSegmentSequential(
|
||||
metricsIterator, result, offset, 0.0, trimStart);
|
||||
}
|
||||
if (trimStop < totalLength) {
|
||||
offset = _appendPathSegmentSequential(
|
||||
metricsIterator, result, offset, trimStop, totalLength);
|
||||
}
|
||||
} else {
|
||||
if (trimStart < trimStop) {
|
||||
offset = _appendPathSegmentSequential(
|
||||
metricsIterator, result, offset, trimStart, trimStop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _trimPathSync(
|
||||
Path path, Path result, double startT, double stopT, bool complement) {
|
||||
final PathMetrics metrics = path.computeMetrics();
|
||||
for (final PathMetric metric in metrics) {
|
||||
double length = metric.length;
|
||||
double trimStart = length * startT;
|
||||
double trimStop = length * stopT;
|
||||
if (complement) {
|
||||
if (trimStart > 0.0) {
|
||||
_appendPathSegmentSync(metric, result, 0.0, 0.0, trimStart);
|
||||
}
|
||||
if (trimStop < length) {
|
||||
_appendPathSegmentSync(metric, result, 0.0, trimStop, length);
|
||||
}
|
||||
} else {
|
||||
if (trimStart < trimStop) {
|
||||
_appendPathSegmentSync(metric, result, 0.0, trimStart, trimStop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateTrimPath(Path path, Path result, double startT, double stopT,
|
||||
bool complement, bool isSequential) {
|
||||
if (isSequential) {
|
||||
_trimPathSequential(path, result, startT, stopT, complement);
|
||||
} else {
|
||||
_trimPathSync(path, result, startT, stopT, complement);
|
||||
}
|
||||
}
|
@ -33,16 +33,18 @@ class Shape extends ShapeBase with ShapePaintContainer {
|
||||
return paths.add(path);
|
||||
}
|
||||
|
||||
void pathChanged(Path path) {
|
||||
void _markComposerDirty() {
|
||||
_pathComposer?.addDirt(ComponentDirt.path);
|
||||
invalidateStrokeEffects();
|
||||
}
|
||||
|
||||
void pathChanged(Path path) => _markComposerDirty();
|
||||
void paintChanged() {
|
||||
addDirt(ComponentDirt.path);
|
||||
for (final d in dependents) {
|
||||
d.addDirt(ComponentDirt.worldTransform);
|
||||
}
|
||||
_pathComposer?.addDirt(ComponentDirt.path);
|
||||
_markComposerDirty();
|
||||
}
|
||||
|
||||
@override
|
||||
@ -60,7 +62,7 @@ class Shape extends ShapeBase with ShapePaintContainer {
|
||||
@override
|
||||
void update(int dirt) {
|
||||
super.update(dirt);
|
||||
if (dirt & ComponentDirt.paint != 0) {
|
||||
if (dirt & ComponentDirt.blendMode != 0) {
|
||||
for (final fill in fills) {
|
||||
fill.blendMode = blendMode;
|
||||
}
|
||||
@ -152,7 +154,7 @@ class Shape extends ShapeBase with ShapePaintContainer {
|
||||
}
|
||||
}
|
||||
|
||||
void _markBlendModeDirty() => addDirt(ComponentDirt.paint);
|
||||
void _markBlendModeDirty() => addDirt(ComponentDirt.blendMode);
|
||||
@override
|
||||
void onPaintMutatorChanged(ShapePaintMutator mutator) {
|
||||
paintChanged();
|
||||
|
@ -14,6 +14,12 @@ abstract class ShapePaintContainer {
|
||||
void onFillsChanged();
|
||||
@protected
|
||||
void onStrokesChanged();
|
||||
void invalidateStrokeEffects() {
|
||||
for (final stroke in strokes) {
|
||||
stroke.invalidateEffects();
|
||||
}
|
||||
}
|
||||
|
||||
bool addFill(Fill fill) {
|
||||
if (fills.add(fill)) {
|
||||
onFillsChanged();
|
||||
|
@ -1,6 +1,6 @@
|
||||
name: rive
|
||||
description: Rive 2 Flutter Runtime
|
||||
version: 0.5.1
|
||||
version: 0.5.2
|
||||
repository: https://github.com/rive-app/rive-flutter
|
||||
homepage: https://rive.app
|
||||
|
||||
|
Reference in New Issue
Block a user