I am searching a way to create a Gradient Icon without using ShaderMask()
.
Why without ShaderMask ?
Because calling saveLayer()
allocates an offscreen buffer. Drawing content into the offscreen buffer might trigger render target switches that are particularly slow in older GPUs. (official flutter documentation)
So here the GradientIcon I have made with the ShaderMask.
import 'package:flutter/material.dart';
class GradientIcon extends StatefulWidget {
final IconData? icon;
final double? size;
final Gradient? gradient;
const GradientIcon({
@required this.icon,
@required this.size,
@required this.gradient,
Key? key
}) : super(key: key);
@override
_GradientIconState createState() => _GradientIconState();
}
class _GradientIconState extends State<GradientIcon> {
double size = 0;
static const iconSizeMultiplier = 1.2;
Shader? shaderFromGradient;
@override
void initState() {
super.initState();
if (widget.size != null)
size = widget.size! * iconSizeMultiplier;
}
@override
Widget build(BuildContext context) {
return ShaderMask(
child: Icon(
widget.icon,
size: size,
color: Colors.white,
),
shaderCallback: (Rect bounds) {
return widget.gradient!.createShader(Rect.fromLTRB(0, 0, size, size));
},
);
}
}
So my question is : Is there a way of rendering Gradient Icon without calling saveLayer()
, so without calling ShaderMask()
?
CodePudding user response:
import 'package:flutter/material.dart';
class GradientIcon extends StatelessWidget {
final IconData icon;
final Gradient gradient;
final double size;
const GradientIcon(
this.icon,
this.gradient,
{
this.size = 24,
Key? key
}
) : super(key: key);
@override
Widget build(BuildContext context) {
return RepaintBoundary(
child: CustomPaint(
size: Size(size, size),
painter: _GradientIconPainter(
icon: icon,
gradient: gradient,
iconSize: size
),
)
);
}
}
class _GradientIconPainter extends CustomPainter {
final IconData? icon;
final Gradient? gradient;
final double? iconSize;
_GradientIconPainter({
Listenable? repaint,
@required this.icon,
@required this.gradient,
@required this.iconSize
}) : super(repaint: repaint);
@override
void paint(Canvas canvas, Size size) {
final Paint _gradientShaderPaint = Paint()
..shader = gradient!.createShader(
Rect.fromLTWH(0.0, 0.0, size.width, size.height)
);
final TextPainter _textPainter = TextPainter(
textDirection: TextDirection.ltr,
text: TextSpan(
text: String.fromCharCode(icon!.codePoint),
style: TextStyle(
foreground: _gradientShaderPaint,
fontFamily: icon!.fontFamily,
fontSize: iconSize
),
)
);
_textPainter.layout(
minWidth: 0,
maxWidth: size.width,
);
final xCenter = (size.width - _textPainter.width) / 2;
final yCenter = (size.height - _textPainter.height) / 2;
final offset = Offset(xCenter, yCenter);
_textPainter.paint(canvas, offset);
}
@override
bool shouldRepaint(_GradientIconPainter oldDelegate) {
return icon != oldDelegate.icon || gradient != oldDelegate.gradient ||
iconSize != oldDelegate.iconSize;
}
}