Skip to content

Instantly share code, notes, and snippets.

@orihpt
Last active February 1, 2025 15:25
Show Gist options
  • Save orihpt/58546ff5961838021fa548a97f61978c to your computer and use it in GitHub Desktop.
Save orihpt/58546ff5961838021fa548a97f61978c to your computer and use it in GitHub Desktop.
Inner Shadow in Flutter that actually works
// An inner shadow that fucking works. Thanks Flutter team "developers" and internet losers for wasting my time.
import 'dart:ui';
import 'package:flutter/material.dart';
class InnerShadow extends StatelessWidget {
final Widget child;
final double blurRadius;
final Radius radius;
final Offset offset;
final Color color;
final double opacity;
const InnerShadow({
required this.child,
this.blurRadius = 10,
this.radius = const Radius.circular(0),
this.offset = const Offset(0, 0),
this.color = Colors.black,
this.opacity = 1,
super.key,
});
@override
Widget build(BuildContext context) {
return Stack(
children: [
child,
Positioned.fill(
child: ClipRRect(
borderRadius: BorderRadius.all(radius),
clipBehavior: Clip.antiAlias,
child: LayoutBuilder(
builder: (context, constraints) {
final outerWidth = constraints.maxWidth * 2;
final outerHeight = constraints.maxHeight * 2;
final width = constraints.maxWidth;
final height = constraints.maxHeight;
return OverflowBox(
maxWidth: outerWidth,
minWidth: outerWidth,
maxHeight: outerHeight,
minHeight: outerHeight,
child: Transform.translate(
offset: offset,
child: ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: blurRadius, sigmaY: blurRadius),
child: SizedBox(
width: outerWidth,
height: outerHeight,
child: ClipPath(
clipper: HoleClipper(radius: radius, size: constraints.biggest),
child: Container(
width: width,
height: height,
color: color.withAlpha((opacity * 255).toInt()),
),
),
),
),
),
);
},
),
),
),
],
);
}
}
class HoleClipper extends CustomClipper<Path> {
final Radius radius;
final Size size;
HoleClipper({this.radius = Radius.zero, required this.size});
@override
Path getClip(Size size) {
Path path = Path()..addRect(Rect.fromLTWH(0, 0, size.width, size.height));
Rect hole = Rect.fromCenter(
center: Offset(size.width / 2, size.height / 2),
width: this.size.width,
height: this.size.height,
);
path.addRRect(RRect.fromRectAndRadius(hole, radius));
return Path.combine(PathOperation.difference, path, Path()..addRRect(RRect.fromRectAndRadius(hole, radius)));
}
@override
bool shouldReclip(HoleClipper oldClipper) => oldClipper.radius != radius || oldClipper.size != size;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment