2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Nuper in scribendo Flutter occupatus sum ad crucis terminales accommodandas, communes codices Android, iOS, et HarmonyOS ad sustentationem gratuita reducendi Android indigena cum particula textus maximum numerum linearum excedit. In primis familiare non fui, itaque primum usus sum Stack ad maxLines et redundantiam alacriter regere, et larvam et textum in angulo dextro inferiore ad illud assequendum inveni textus integitur et dimidium verbi effluat, hodie tandem tempus est ad exsequendum consilium optimize.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class ExpandableText extends StatefulWidget {
final String text;
final int maxLines;
final TextStyle textStyle;
final String linkTextExpand;
final String linkTextCollapse;
final Color linkTextColor;
const ExpandableText(
{super.key,
required this.text,
this.maxLines = 2,
this.textStyle = const TextStyle(color: Colors.black),
this.linkTextColor = Colors.blue,
this.linkTextExpand = " 展开",
this.linkTextCollapse = " 收起"});
State<StatefulWidget> createState() => _ExpandableTextState();
}
class _ExpandableTextState extends State<ExpandableText> {
bool isExpanded = false;
late TextSpan expandSpan;
late TextSpan linkTextSpan;
void initState() {
super.initState();
expandSpan = TextSpan(
text: widget.linkTextExpand,
style: TextStyle(color: widget.linkTextColor),
recognizer: TapGestureRecognizer()
..onTap = () {
setState(() {
isExpanded = !isExpanded;
});
},
);
linkTextSpan = TextSpan(
text: '...',
style: widget.textStyle,
children: [expandSpan],
);
}
/// 检查文本是否溢出
bool checkOverflow(double width) {
final textPainter = TextPainter(
text: TextSpan(text: widget.text, style: widget.textStyle),
textDirection: TextDirection.ltr,
);
textPainter.layout(maxWidth: width);
return textPainter.height > widget.maxLines * textPainter.preferredLineHeight;
}
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final maxWidth = constraints.maxWidth;
final textSpan = TextSpan(
text: widget.text,
style: widget.textStyle,
);
final textPainter = TextPainter(
text: textSpan,
maxLines: isExpanded ? null : widget.maxLines,
textDirection: TextDirection.ltr,
);
textPainter.layout(maxWidth: maxWidth);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
isExpanded ? _buildExpandedText() : _buildCollapsedText(textPainter, maxWidth),
],
);
},
);
}
/// 构建折叠状态下的文本
Widget _buildCollapsedText(TextPainter textPainter, double maxWidth) {
var truncatedText = widget.text;
if (checkOverflow(maxWidth)) {
// 文本的长度超过了最大行数,需要截取然后拼接展开部分的逻辑
final linkPainter = TextPainter(
text: linkTextSpan,
textDirection: TextDirection.ltr,
);
linkPainter.layout(maxWidth: maxWidth);
final position = textPainter.getPositionForOffset(Offset(maxWidth - linkPainter.width, textPainter.height));
final endOffset = textPainter.getOffsetBefore(position.offset) ?? position.offset;
truncatedText = widget.text.substring(0, endOffset);
}
return RichText(
text: TextSpan(
text: truncatedText,
style: widget.textStyle,
children: widget.text.length == truncatedText.length ? [] : [linkTextSpan],
),
maxLines: widget.maxLines,
overflow: TextOverflow.ellipsis,
);
}
/// 构建展开状态下的文本
Widget _buildExpandedText() {
final collapseSpan = TextSpan(
text: widget.linkTextCollapse,
style: TextStyle(color: widget.linkTextColor),
recognizer: TapGestureRecognizer()
..onTap = () {
setState(() {
isExpanded = !isExpanded;
});
},
);
return RichText(
text: TextSpan(
text: widget.text,
style: widget.textStyle,
children: [collapseSpan],
),
);
}
}
ExpandableText consuetudo est Flutter content usus ad longum textum contentum proponere. Cum textus longitudo praesens maximum numerum linearum excedit, textus corruet et nexus "expand" proponendum.
Utere StatefulWidget et _ExpandableTextState ad tractandum expansum/concidit statum textus.
Variabilis isExpanded statum rei textus ostentationis moderatur.
Utere textuPainter et in RichText componentibus ut textum metiendi et reddendi.
Cum textus numerus linearum maximam excedit, textum computando et intercipiendo, ut textus recte in statu collapso exponatur, et nexum "expand" addat.
Click eventum addere magna per TapGestureRecognizer ad operandum functiones "expand" et "colla".
Modus setState usus est ut status textus ostentationis update.
Utere LayoutBuilder ut amplitudines inversas obtineas ut diversas magnitudinum screen et ambitus culturas accommodare.
Methodus checkOverflow adhibetur ad dijudicandum num textus maximam numerum linearum excedat.
Plures parametros configurabiles praebet, ut maxLines, textor, pagina textExpand, nexusCollapse, nexusColor, permittens utentes formas et mores in textu.
ExpandableText(
text: "这是一段很长的文本,它将被折叠起来,只有在点击'展开'链接后才会完全显示。",
maxLines: 2,
textStyle: TextStyle(fontSize: 16, color: Colors.black),
linkTextExpand: " 展开",
linkTextCollapse: " 收起",
linkTextColor: Colors.blue,
);
Fac cum usura ExpandableText ut textum satis contextum praebeas ut punctum plicae textus recte computetur.
Parametri styli consuetudo aptari debet secundum actuales necessitates ad optimum effectum visualem consequendum.