Skip to content

Instantly share code, notes, and snippets.

@flar
Created June 18, 2025 20:48
Show Gist options
  • Save flar/8611159b3b01cb0ad2b64b7cb8fafa87 to your computer and use it in GitHub Desktop.
Save flar/8611159b3b01cb0ad2b64b7cb8fafa87 to your computer and use it in GitHub Desktop.
Shadow performance on various shapes
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
showPerformanceOverlay: true,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({super.key, required this.title});
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
enum ShadowType { rect, uniform_round_rect, uneven_round_rect, triangle, hourglass }
class ShadowPainter extends CustomPainter {
ShadowPainter({
required this.rows,
required this.cols,
required this.redIndex,
required this.shadowType,
required this.drawShape,
});
final int rows;
final int cols;
final int redIndex;
final bool drawShape;
final ShadowType shadowType;
Path shadow(Rect fgRect, double x, double y) {
Rect rect = fgRect.translate(x, y);
switch (shadowType) {
case ShadowType.rect:
return Path()..addRect(rect);
case ShadowType.uniform_round_rect:
return Path()..addRRect(RRect.fromRectXY(rect, 4, 4));
case ShadowType.uneven_round_rect:
return Path()..addRRect(RRect.fromRectXY(rect, 3, 4));
case ShadowType.triangle:
return Path()
..moveTo(rect.topLeft.dx, rect.topLeft.dy)
..lineTo(rect.bottomCenter.dx, rect.bottomCenter.dy)
..lineTo(rect.topRight.dx, rect.topRight.dy)
..close();
case ShadowType.hourglass:
return Path()
..moveTo(rect.topLeft.dx, rect.topLeft.dy)
..lineTo(rect.bottomRight.dx, rect.bottomRight.dy)
..lineTo(rect.topRight.dx, rect.topRight.dy)
..lineTo(rect.bottomLeft.dx, rect.bottomLeft.dy)
..close();
}
}
@override
void paint(Canvas canvas, Size size) {
double w = size.width / cols;
double h = size.height / rows;
Rect fgRect = Offset(w/4, h/4) & Size(w / 2, h / 2);
int index = 0;
Paint p = Paint()..style = PaintingStyle.fill;
for (double y = 0; y < size.height; y += h) {
for (double x = 0; x < size.width; x += w) {
Path path = shadow(fgRect, x, y);
canvas.drawShadow(path, Colors.black, 5, true);
if (drawShape) {
p.color = (index++ == redIndex) ? Colors.red : Colors.green;
canvas.drawPath(path, p);
}
}
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
static int _rows = 20;
static int _cols = 10;
int _redIndex = 0;
bool _drawShape = true;
ShadowType _shadowType = ShadowType.rect;
late AnimationController _controller;
@override
void initState() {
super.initState();
_redIndex = 0;
_drawShape = true;
_shadowType = ShadowType.rect;
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 1),
);
_controller.repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void bump() {
if (_redIndex++ >= _rows * _cols) _redIndex = 0;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AnimatedBuilder(
animation: _controller,
child: Container(),
builder: (context, child) {
bump();
return Expanded(
child: CustomPaint(
isComplex: false,
willChange: true,
painter: ShadowPainter(
rows: _rows,
cols: _cols,
redIndex: _redIndex,
shadowType: _shadowType,
drawShape: _drawShape,
),
child: child,
),
);
},
),
],
),
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Shadow shape: '),
DropdownMenu(
initialSelection: _shadowType,
dropdownMenuEntries: ShadowType.values.map((e) =>
DropdownMenuEntry(
value: e,
label: '$e',
)
).toList(),
onSelected: (value) {
setState(() {
_shadowType = value!;
});
},
),
SizedBox(width: 50),
Text('Draw shape: '),
Checkbox(
value: _drawShape,
onChanged: (value) {
setState(() {
_drawShape = value!;
});
},
)
],
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment