Created
June 18, 2025 20:48
-
-
Save flar/8611159b3b01cb0ad2b64b7cb8fafa87 to your computer and use it in GitHub Desktop.
Shadow performance on various shapes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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