'How to decorate text stroke in Flutter?
How to decorate text stroke in Flutter? It's like -webkit-text-stroke - CSS
Solution 1:[1]
Stroke has been possible without workarounds since the addition of foreground paints in TextStyle. An explicit example of stroke under fill bordered text has been added in the TextStyle documentation: https://master-api.flutter.dev/flutter/painting/TextStyle-class.html#painting.TextStyle.6
This example is reproduced here:
Stack(
children: <Widget>[
// Stroked text as border.
Text(
'Greetings, planet!',
style: TextStyle(
fontSize: 40,
foreground: Paint()
..style = PaintingStyle.stroke
..strokeWidth = 6
..color = Colors.blue[700],
),
),
// Solid text as fill.
Text(
'Greetings, planet!',
style: TextStyle(
fontSize: 40,
color: Colors.grey[300],
),
),
],
)
Stroke by itself is possible by removing the Stack and just using the first stroke Text widget by itself. The stroke/fill order can also be adjusted by swapping the first and second Text widget.
Solution 2:[2]
I was also looking for this, wasn't able to find it. But I did find a workaround using 4 shadows in the TextStyle:
Text("Border test",
style: TextStyle(
inherit: true,
fontSize: 48.0,
color: Colors.pink,
shadows: [
Shadow( // bottomLeft
offset: Offset(-1.5, -1.5),
color: Colors.white
),
Shadow( // bottomRight
offset: Offset(1.5, -1.5),
color: Colors.white
),
Shadow( // topRight
offset: Offset(1.5, 1.5),
color: Colors.white
),
Shadow( // topLeft
offset: Offset(-1.5, 1.5),
color: Colors.white
),
]
),
);
I also opened an Issue on GitHub: https://github.com/flutter/flutter/issues/24108
Solution 3:[3]
Inspired by this article, to achieve the effect, I prefer to use a technique that mixes two Text widgets and TextStype.foreground property with custom Paint():
class StrokeText extends StatelessWidget {
final String text;
final double fontSize;
final FontWeight fontWeight;
final Color color;
final Color strokeColor;
final double strokeWidth;
const StrokeText(
this.text, {
Key key,
this.fontSize,
this.fontWeight,
this.color,
this.strokeColor,
this.strokeWidth,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: [
Text(
text,
style: TextStyle(
fontSize: fontSize,
fontWeight: fontWeight,
foreground: Paint()..color = color,
),
),
Text(
text,
style: TextStyle(
fontSize: fontSize,
fontWeight: fontWeight,
foreground: Paint()
..strokeWidth = strokeWidth
..color = strokeColor
..style = PaintingStyle.stroke,
),
),
],
);
}
}
Solution 4:[4]
If you prefer the shadows method, you can configure the stroke width using :
/// Outlines a text using shadows.
static List<Shadow> outlinedText({double strokeWidth = 2, Color strokeColor = Colors.black, int precision = 5}) {
Set<Shadow> result = HashSet();
for (int x = 1; x < strokeWidth + precision; x++) {
for(int y = 1; y < strokeWidth + precision; y++) {
double offsetX = x.toDouble();
double offsetY = y.toDouble();
result.add(Shadow(offset: Offset(-strokeWidth / offsetX, -strokeWidth / offsetY), color: strokeColor));
result.add(Shadow(offset: Offset(-strokeWidth / offsetX, strokeWidth / offsetY), color: strokeColor));
result.add(Shadow(offset: Offset(strokeWidth / offsetX, -strokeWidth / offsetY), color: strokeColor));
result.add(Shadow(offset: Offset(strokeWidth / offsetX, strokeWidth / offsetY), color: strokeColor));
}
}
return result.toList();
}
Use it like this :
Text(
'My text',
style: TextStyle(shadows: outlinedText(strokeColor: Colors.blue)),
);
Solution 5:[5]
Inspired by @Gary Qian's answer
Widget textWithStroke({String text, String fontFamily, double fontSize: 12, double strokeWidth: 1, Color textColor: Colors.white, Color strokeColor: Colors.black}) {
return Stack(
children: <Widget>[
Text(
text,
style: TextStyle(
fontSize: fontSize,
fontFamily: fontFamily,
foreground: Paint()
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth
..color = strokeColor,
),
),
Text(text, style: TextStyle(fontFamily: fontFamily, fontSize: fontSize, color: textColor)),
],
);
}
Solution 6:[6]
I created a package using the same logic shared here.
I also make it possible to add multiple strokes at once.
Solution 7:[7]
This is @Aleh's answer migrated to null-safety and with some more flexibility. Simply paste this inside a new file, and use freely.
import 'package:flutter/widgets.dart';
/// Places a stroke around text to make it appear outlined
///
/// Adapted from https://stackoverflow.com/a/55559435/11846040
class OutlinedText extends StatelessWidget {
/// Text to display
final String text;
/// Original text style (if you weren't outlining)
///
/// Do not specify `color` inside this: use [textColor] instead.
final TextStyle style;
/// Text color
final Color textColor;
/// Outline stroke color
final Color strokeColor;
/// Outline stroke width
final double strokeWidth;
/// Places a stroke around text to make it appear outlined
///
/// Adapted from https://stackoverflow.com/a/55559435/11846040
const OutlinedText(
this.text, {
Key? key,
this.style = const TextStyle(),
required this.textColor,
required this.strokeColor,
required this.strokeWidth,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: [
Text(
text,
style: style.copyWith(foreground: Paint()..color = textColor),
),
Text(
text,
style: style.copyWith(
foreground: Paint()
..strokeWidth = strokeWidth
..color = strokeColor
..style = PaintingStyle.stroke,
),
),
],
);
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Gary Qian |
Solution 2 | PieterAelse |
Solution 3 | Aleh |
Solution 4 | |
Solution 5 | New Dev |
Solution 6 | Jorge Wander Santana UreƱa |
Solution 7 | JaffaKetchup |