我有一个应用程序在背景图像前显示带有文本的内容卡。为了更好的可读性,在文本和背景图像之间添加了一个模糊层。由于在构建之前获取小部件(或文本)的高度并不容易,因此我能找到解决此问题的唯一方法(不使用回调或重绘)是 LineMetrics。使用 LineMetrics,我可以计算文本以正确大小绘制模糊层所需的空间。
现在问题来了:LineMetrics 的计算width
属性有时不适合呈现的文本宽度。这在导致换行丢失的情况下是有问题的,因为模糊的背景不再覆盖整个文本区域。
我在做什么:在这篇中篇文章之后,我首先创建了一个带有文本和样式的 TextSpan,然后将其添加到 TextPainter 中,然后使用, 和调用该layout()
函数。最后,我使用以下命令创建 LineMetrics :minWidth: 0
maxWidth: maxTextWidth
textPainter.computeLineMetrics()
// Widget
@override
Widget build(BuildContext context) {
// Get text styles
final TextStyle titleStyle = TextStyle(
fontFamily: 'SF Pro Display',
fontStyle: FontStyle.normal,
fontSize: 14,
height: (17 / 14),
fontWeight: FontWeight.bold,
color: Colors.white);
final TextStyle textStyle = TextStyle(
fontFamily: 'SF Pro Display',
fontStyle: FontStyle.normal,
fontSize: 14,
height: (17 / 14),
fontWeight: FontWeight.normal,
color: Colors.white);
// Build text spans
final titleSpan = TextSpan(text: title, style: titleStyle);
final textSpan = TextSpan(text: text, style: textStyle);
// Calculate text metrics
final double _maxWidth = style.width - style.margin.horizontal;
List<LineMetrics> _titleLines = _getLineMetrics(_maxWidth, titleSpan);
List<LineMetrics> _textLines = _getLineMetrics(_maxWidth, textSpan);
// Calculate text heights
final double _titleHeight = _getLinesHeight(_titleLines) + style.margin.top;
final double _textHeight = _getLinesHeight(_textLines) + style.margin.bottom;
// Generate coloured debug container
Column _titleContainer = _getTextSpanContainer(_titleLines);
Column _textContainer = _getTextSpanContainer(_textLines);
// Widget content
List<Widget> _textOverlay = [
Expanded(child: Text('')),
Stack(children: <Widget>[
Align(alignment: Alignment.topLeft, child: _titleContainer),
Align(alignment: Alignment.topLeft, child: RichText(text: titleSpan))
]),
Stack(children: <Widget>[
Align(alignment: Alignment.topLeft, child: _textContainer),
Align(alignment: Alignment.topLeft, child: RichText(text: textSpan))
])
];
List<LineMetrics> _getLineMetrics(double width, TextSpan textSpan) {
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr
);
textPainter.layout(
minWidth: 0,
maxWidth: width,
);
// TODO: width of lineMetrics sometimes not matching real text width
return textPainter.computeLineMetrics();
}
double _getLinesHeight(List<LineMetrics> lines) {
double _textHeight = 0;
for (LineMetrics line in lines) {
_textHeight += line.height;
}
return _textHeight;
}
Column _getTextSpanContainer(List<LineMetrics> lines) {
List<Widget> container = [];
for (LineMetrics line in lines) {
container.add(Container(
width: line.width,
height: line.height,
color: Colors.red,
));
}
return Column(
children: container,
crossAxisAlignment: CrossAxisAlignment.start,
);
}
我在每个文本行后面添加了带有 LineMetrics 计算宽度的红色轮廓,以可视化问题。大多数情况下它可以工作,但有时计算出的宽度不匹配:
我尝试了 TextStyles 中几乎所有可能的属性(WordSpacing、LetterSpacing、textWidthBasis ...),使用和不使用自定义字体构建它,使用 RichText 和普通文本元素进行绘制,但所描述的问题没有任何变化。
任何人都可以帮助解决这种奇怪的行为,或者在构建小部件之前提供一种替代方法来获取文本高度吗?
一些相关问题: