Skip to content

Instantly share code, notes, and snippets.

@filiph
Created March 6, 2020 00:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save filiph/e13882ff785d98d0bcd2bf12fff4e9df to your computer and use it in GitHub Desktop.
Save filiph/e13882ff785d98d0bcd2bf12fff4e9df to your computer and use it in GitHub Desktop.
RepaintBoundary sample
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ColorFilterAndFadePage(),
);
}
}
// This tests whether the Opacity layer raster cache works with color filters.
// See https://github.com/flutter/flutter/issues/51975.
class ColorFilterAndFadePage extends StatefulWidget {
@override
_ColorFilterAndFadePageState createState() => _ColorFilterAndFadePageState();
}
class _ColorFilterAndFadePageState extends State<ColorFilterAndFadePage>
with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
final Widget shadowWidget = _ShadowWidget(
width: 24,
height: 24,
color: _useColorFilter ? Colors.white : null,
shadow: ui.Shadow(
color: Colors.black45,
offset: const Offset(0.0, 2.0),
blurRadius: 4.0,
),
);
final Widget row = Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
shadowWidget,
const SizedBox(width: 12),
shadowWidget,
const SizedBox(width: 12),
shadowWidget,
const SizedBox(width: 12),
shadowWidget,
const SizedBox(width: 12),
shadowWidget,
const SizedBox(width: 12),
],
);
final Widget column = Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
row,
const SizedBox(height: 12),
row,
const SizedBox(height: 12),
row,
const SizedBox(height: 12),
row,
const SizedBox(height: 12),
],
);
final Widget fadeTransition = FadeTransition(
opacity: _opacityAnimation,
// This RepaintBoundary is necessary to not let the opacity change
// invalidate the layer raster cache below. This is necessary with
// or without the color filter.
child: RepaintBoundary(
child: column,
),
);
return Scaffold(
backgroundColor: Colors.lightBlue,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
fadeTransition,
Container(height: 20),
const Text('Use Color Filter:'),
Checkbox(
value: _useColorFilter,
onChanged: (bool value) {
setState(() {
_useColorFilter = value;
});
},
),
],
),
),
);
}
// Create a looping fade-in fade-out animation for opacity.
void _initAnimation() {
_controller =
AnimationController(duration: const Duration(seconds: 3), vsync: this);
_opacityAnimation =
Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
_opacityAnimation.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
_controller.reverse();
} else if (status == AnimationStatus.dismissed) {
_controller.forward();
}
});
_controller.forward();
}
@override
void initState() {
super.initState();
_initAnimation();
}
AnimationController _controller;
Animation<double> _opacityAnimation;
bool _useColorFilter = true;
}
class _ShadowWidget extends StatelessWidget {
const _ShadowWidget({
@required this.width,
@required this.height,
@required this.color,
@required this.shadow,
});
final double width;
final double height;
final Color color;
final Shadow shadow;
@override
Widget build(BuildContext context) {
return SizedBox(
width: width,
height: height,
child: CustomPaint(
painter: _ShadowPainter(
color: color,
shadow: shadow,
),
size: Size(width, height),
isComplex: true,
willChange: false,
),
);
}
}
class _ShadowPainter extends CustomPainter {
const _ShadowPainter({this.color, @required this.shadow});
// If null, we'll set no color filter.
final Color color;
final Shadow shadow;
@override
void paint(Canvas canvas, Size size) {
final Rect rect = Offset.zero & size;
final Paint paint = Paint();
if (color != null) {
paint.colorFilter = ColorFilter.mode(shadow.color, BlendMode.srcIn);
}
canvas.saveLayer(null, paint);
canvas.translate(shadow.offset.dx, shadow.offset.dy);
canvas.drawRect(rect, Paint());
canvas.drawRect(
rect,
Paint()
..maskFilter = MaskFilter.blur(BlurStyle.normal, shadow.blurSigma));
canvas.restore();
canvas.drawRect(rect, Paint()..color = color ?? Colors.black);
}
@override
bool shouldRepaint(_ShadowPainter oldDelegate) => oldDelegate.color != color;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment