Skip to content

Instantly share code, notes, and snippets.

@hawkkiller
Last active January 24, 2025 08:03
Show Gist options
  • Select an option

  • Save hawkkiller/032ccc81c01bc0754340b7ef138e8ce8 to your computer and use it in GitHub Desktop.

Select an option

Save hawkkiller/032ccc81c01bc0754340b7ef138e8ce8 to your computer and use it in GitHub Desktop.
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
class AnimatedEdgeSlide extends SingleChildRenderObjectWidget {
const AnimatedEdgeSlide({
required Widget super.child,
required this.positionAnimation,
super.key,
});
final Animation<double> positionAnimation;
@override
RenderObject createRenderObject(BuildContext context) {
return RenderAnimatedEdgeSlide(
positionAnimation: positionAnimation,
);
}
@override
void updateRenderObject(BuildContext context, covariant RenderObject renderObject) {
(renderObject as RenderAnimatedEdgeSlide).positionAnimation = positionAnimation;
}
}
class RenderAnimatedEdgeSlide extends RenderProxyBox {
RenderAnimatedEdgeSlide({
required Animation<double> positionAnimation,
}) : _positionAnimation = positionAnimation;
Animation<double> get positionAnimation => _positionAnimation;
Animation<double> _positionAnimation;
set positionAnimation(Animation<double> value) {
if (value == _positionAnimation) {
return;
}
if (attached) {
_positionAnimation.removeListener(_animationListener);
}
_positionAnimation = value;
if (attached) {
_positionAnimation.addListener(_animationListener);
}
}
@override
void attach(covariant PipelineOwner owner) {
super.attach(owner);
_positionAnimation.addListener(_animationListener);
}
@override
void detach() {
_positionAnimation.removeListener(_animationListener);
super.detach();
}
void _animationListener() => markNeedsLayout();
@override
void performLayout() {
final child = this.child;
if (child == null || _positionAnimation.value == 0) {
size = Size.zero;
return;
}
child.layout(constraints, parentUsesSize: true);
size = Size(
child.size.width * _positionAnimation.value,
constraints.maxHeight,
);
}
final LayerHandle<ClipRectLayer> _clipRectLayer = LayerHandle<ClipRectLayer>();
@override
void paint(PaintingContext context, Offset offset) {
if (child == null || _positionAnimation.value <= 0) {
// Ensure the layer is reset if the child is null or animation value is zero
_clipRectLayer.layer = null;
return;
}
// Apply clipping and cache the layer
_clipRectLayer.layer = context.pushClipRect(
needsCompositing,
offset,
Offset.zero & size, // Clip to the current size
super.paint,
oldLayer: _clipRectLayer.layer,
);
}
@override
void dispose() {
_positionAnimation.removeListener(_animationListener);
_clipRectLayer.layer = null;
super.dispose();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment