diff --git a/.rive_head b/.rive_head index 466dca7..ed532e6 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -da903372b918a5ad3f86439a944b9dddb8c5a785 +ee674a819b3e4af245cb5b33bc60bab2741079ce diff --git a/lib/src/rive_core/shapes/path.dart b/lib/src/rive_core/shapes/path.dart index 1e176f4..47e8413 100644 --- a/lib/src/rive_core/shapes/path.dart +++ b/lib/src/rive_core/shapes/path.dart @@ -309,6 +309,15 @@ abstract class Path extends PathBase { void pathFlagsChanged(int from, int to) => markPathDirty(); bool get isHidden => (pathFlags & ComponentFlags.hidden) != 0; + + @override + bool propagateCollapse(bool collapse) { + bool changed = super.propagateCollapse(collapse); + if (changed && shape != null) { + shape!.pathCollapseChanged(); + } + return changed; + } } enum _PathCommand { moveTo, lineTo, cubicTo, close } diff --git a/lib/src/rive_core/shapes/path_composer.dart b/lib/src/rive_core/shapes/path_composer.dart index 45c1fa7..2d4f25b 100644 --- a/lib/src/rive_core/shapes/path_composer.dart +++ b/lib/src/rive_core/shapes/path_composer.dart @@ -37,7 +37,7 @@ class PathComposer extends Component { Mat2D inverseWorld = Mat2D(); if (Mat2D.invert(inverseWorld, world)) { for (final path in shape.paths) { - if (path.isHidden) { + if (path.isHidden || path.isCollapsed) { continue; } localPath.addPath(path.uiPath, ui.Offset.zero, @@ -56,7 +56,7 @@ class PathComposer extends Component { if (buildWorldPath) { worldPath.reset(); for (final path in shape.paths) { - if (path.isHidden) { + if (path.isHidden || path.isCollapsed) { continue; } worldPath.addPath(path.uiPath, ui.Offset.zero, @@ -99,4 +99,19 @@ class PathComposer extends Component { onDirty(dirt); artboard?.onComponentDirty(this); } + + // Instead of adding dirt and rely on the recursive behavior of the addDirt method, + // we need to explicitly add dirt to the dependents. The reason is that a collapsed + // shape will not clear its dirty path flag in the current frame since it is collapsed. + // So in a future frame if it is uncollapsed, we mark its path flag as dirty again, + // but since it was already dirty, the recursive part will not kick in and the dependents + // won't update. + // This scenario is not common, but it can happen when a solo toggles between an empty + // group and a path for example. + void pathCollapseChanged() { + addDirt(ComponentDirt.path); + for (final d in dependents) { + d.addDirt(ComponentDirt.path, recurse: true); + } + } } diff --git a/lib/src/rive_core/shapes/shape.dart b/lib/src/rive_core/shapes/shape.dart index f7f2f59..989fb39 100644 --- a/lib/src/rive_core/shapes/shape.dart +++ b/lib/src/rive_core/shapes/shape.dart @@ -72,6 +72,8 @@ class Shape extends ShapeBase with ShapePaintContainer { void pathChanged(Path path) => _markComposerDirty(); + void pathCollapseChanged() => pathComposer.pathCollapseChanged(); + void paintChanged() { addDirt(ComponentDirt.path); _markBlendModeDirty(); @@ -314,4 +316,10 @@ class Shape extends ShapeBase with ShapePaintContainer { path.buildPath(hitTester); } } + + @override + bool propagateCollapse(bool collapse) { + propagateCollapseToChildren(collapse); + return super.propagateCollapse(collapse); + } }