在Flutter中判断文本是否超出三行,可以使用以下几种方法:
方法一:使用TextPainter(推荐)
class TextLineChecker extends StatelessWidget {
final String text;
final TextStyle style;
final double maxWidth;
const TextLineChecker({
Key? key,
required this.text,
required this.style,
required this.maxWidth,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 显示文本
Container(
width: maxWidth,
child: Text(
text,
style: style,
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
),
// 判断是否超过三行
FutureBuilder<bool>(
future: _isTextExceedingThreeLines(),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data == true) {
return TextButton(
onPressed: () {
// 处理展开/收起逻辑
},
child: Text('展开'),
);
}
return SizedBox.shrink();
},
),
],
);
}
Future<bool> _isTextExceedingThreeLines() async {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style),
maxLines: 3,
textDirection: TextDirection.ltr,
)..layout(maxWidth: maxWidth);
// 判断是否被截断
return textPainter.didExceedMaxLines;
}
}
方法二:同步判断(使用StatefulWidget)
class TextLineCheckWidget extends StatefulWidget {
final String text;
final TextStyle style;
final double maxWidth;
const TextLineCheckWidget({
Key? key,
required this.text,
required this.style,
required this.maxWidth,
}) : super(key: key);
@override
_TextLineCheckWidgetState createState() => _TextLineCheckWidgetState();
}
class _TextLineCheckWidgetState extends State<TextLineCheckWidget> {
bool _isExceeding = false;
bool _isExpanded = false;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_checkTextLines();
});
}
void _checkTextLines() {
final TextPainter textPainter = TextPainter(
text: TextSpan(
text: widget.text,
style: widget.style,
),
maxLines: 3,
textDirection: TextDirection.ltr,
)..layout(maxWidth: widget.maxWidth);
setState(() {
_isExceeding = textPainter.didExceedMaxLines;
});
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.text,
style: widget.style,
maxLines: _isExpanded ? null : 3,
overflow: _isExpanded ? null : TextOverflow.ellipsis,
),
if (_isExceeding)
TextButton(
onPressed: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
child: Text(_isExpanded ? '收起' : '展开'),
),
],
);
}
}
方法三:使用LayoutBuilder获取宽度
class TextLineChecker extends StatefulWidget {
final String text;
final TextStyle style;
const TextLineChecker({
Key? key,
required this.text,
required this.style,
}) : super(key: key);
@override
_TextLineCheckerState createState() => _TextLineCheckerState();
}
class _TextLineCheckerState extends State<TextLineChecker> {
bool _isExceeding = false;
bool _isExpanded = false;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
// 获取可用宽度
final maxWidth = constraints.maxWidth;
// 检查是否超过三行
WidgetsBinding.instance.addPostFrameCallback((_) {
_checkTextLines(maxWidth);
});
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.text,
style: widget.style,
maxLines: _isExpanded ? null : 3,
overflow: _isExpanded ? null : TextOverflow.ellipsis,
),
if (_isExceeding)
TextButton(
onPressed: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
child: Text(_isExpanded ? '收起' : '展开'),
),
],
);
},
);
}
void _checkTextLines(double maxWidth) {
final TextPainter textPainter = TextPainter(
text: TextSpan(
text: widget.text,
style: widget.style,
),
maxLines: 3,
textDirection: TextDirection.ltr,
)..layout(maxWidth: maxWidth);
if (_isExceeding != textPainter.didExceedMaxLines) {
setState(() {
_isExceeding = textPainter.didExceedMaxLines;
});
}
}
}
方法四:简单的工具函数
class TextUtils {
static Future<bool> isTextExceedingLines({
required String text,
required TextStyle style,
required double maxWidth,
int maxLines = 3,
}) async {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style),
maxLines: maxLines,
textDirection: TextDirection.ltr,
)..layout(maxWidth: maxWidth);
return textPainter.didExceedMaxLines;
}
}
// 使用示例
class MyWidget extends StatelessWidget {
final String text = "这是一段很长的文本...";
@override
Widget build(BuildContext context) {
return FutureBuilder<bool>(
future: TextUtils.isTextExceedingLines(
text: text,
style: TextStyle(fontSize: 16),
maxWidth: 300,
),
builder: (context, snapshot) {
return Column(
children: [
Text(
text,
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
if (snapshot.data == true)
Text('文本超过三行'),
],
);
},
);
}
}
注意事项
1.TextPainter 需要在布局之后才能准确计算
2.使用 addPostFrameCallback 确保在布局完成后计算
3.考虑文本方向(LTR/RTL)
4.注意字体大小、行高等因素会影响行数计算
5.如果使用 maxLines: null,didExceedMaxLines 始终返回 false
推荐使用方法二或方法三,它们提供了完整的展开/收起功能,并且考虑了实际布局情况。