Skip to content

Instantly share code, notes, and snippets.

@flar
Created April 7, 2020 22:25
Show Gist options
  • Save flar/e4b56f1dea6a62609e24e5d387ad668d to your computer and use it in GitHub Desktop.
Save flar/e4b56f1dea6a62609e24e5d387ad668d to your computer and use it in GitHub Desktop.
complex render benchmark for testing animations
import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fading Widget Demo',
home: MyHomePage(title: 'Fading Widget'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
enum FilterType {
OPACITY, ROTATE_TRANSFORM, ROTATE_FILTER,
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
AnimationController _controller;
bool _useRepaintBoundary = false;
bool _complexChild = false;
FilterType _filterType;
GlobalKey _childKey = GlobalKey(debugLabel: 'child to animate');
Offset _childCenter = Offset.zero;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
RenderBox childBox = _childKey.currentContext.findRenderObject();
Offset localCenter = childBox.paintBounds.center;
_childCenter = childBox.localToGlobal(localCenter);
});
_controller = AnimationController(vsync: this, duration: Duration(seconds: 2));
_controller.repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _setFilterType(FilterType type, bool selected) {
setState(() => _filterType = selected ? type : null);
}
List<Widget> makeComplexChildList(int rows, int cols, double w, double h) {
List<Widget> children = <Widget>[];
double sx = w / cols;
double sy = h / rows;
double tx = - sx * cols / 2.0;
double ty = - sy * rows / 2.0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
children.add(RepaintBoundary(child: Transform(
child: Text('text'),
transform: Matrix4.translationValues(c * sx + tx, r * sy + ty, 0.0),
)));
}
}
return children;
}
static Widget _makeChild(int rows, int cols, double fontSize, bool complex) {
BoxDecoration decoration = BoxDecoration(
color: Colors.green,
boxShadow: complex ? <BoxShadow>[
BoxShadow(
color: Colors.black,
blurRadius: 10.0,
),
] : null,
borderRadius: BorderRadius.circular(10.0),
);
return Stack(
alignment: Alignment.center,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List<Widget>.generate(rows, (r) => Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List<Widget>.generate(cols, (c) => Container(
child: Text('text', style: TextStyle(fontSize: fontSize)),
decoration: decoration,
)),
)),
),
Text('child',
style: TextStyle(
color: Colors.white,
fontSize: 36,
),
),
],
);
}
static Widget _protectChild({Widget child, bool protect}) {
if (protect) {
child = RepaintBoundary(child: child,);
}
return child;
}
Widget buildOpacity(BuildContext context, Widget child) {
return Opacity(
opacity: (_controller.value * 2.0 - 1.0).abs(),
child: child,
);
}
Widget _animate(Widget child) {
if (_filterType == null) {
_controller.reset();
return child;
}
_controller.repeat();
Function builder;
switch (_filterType) {
case FilterType.OPACITY:
builder = (context, child) => Opacity(
opacity: (_controller.value * 2.0 - 1.0).abs(),
child: child,
);
break;
case FilterType.ROTATE_TRANSFORM:
builder = (center, child) => Transform(
transform: Matrix4.rotationZ(_controller.value * 2.0 * pi),
alignment: Alignment.center,
child: child,
);
break;
case FilterType.ROTATE_FILTER:
builder = (center, child) => ImageFiltered(
imageFilter: ImageFilter.matrix((
Matrix4.identity()
..translate(_childCenter.dx, _childCenter.dy)
..rotateZ(_controller.value * 2.0 * pi)
..translate(- _childCenter.dx, - _childCenter.dy)
).storage),
child: child,
);
break;
}
return AnimatedBuilder(
animation: _controller,
child: child,
builder: builder,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: _animate(_protectChild(
child: Container(
key: _childKey,
color: Colors.yellow,
width: 300,
height: 300,
child: Center(
child: _makeChild(4, 3, 24.0, _complexChild),
),
),
protect: _useRepaintBoundary,
),
),
),
bottomNavigationBar: BottomAppBar(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Opacity:'),
Checkbox(
value: _filterType == FilterType.OPACITY,
onChanged: (b) => _setFilterType(FilterType.OPACITY, b),
),
Text('Tx Rotate:'),
Checkbox(
value: _filterType == FilterType.ROTATE_TRANSFORM,
onChanged: (b) => _setFilterType(FilterType.ROTATE_TRANSFORM, b),
),
Text('IF Rotate:'),
Checkbox(
value: _filterType == FilterType.ROTATE_FILTER,
onChanged: (b) => _setFilterType(FilterType.ROTATE_FILTER, b),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Complex child:'),
Checkbox(
value: _complexChild,
onChanged: (b) => setState(() => _complexChild = b),
),
Text('RPB on child:'),
Checkbox(
value: _useRepaintBoundary,
onChanged: (b) => setState(() => _useRepaintBoundary = b),
),
],
),
],
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment