내 연락처 정보
우편메소피아@프로톤메일.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
최근에는 크로스 터미널에 적응하기 위해 Flutter를 작성하느라 바빴고, 인건비를 줄이기 위해 Android, iOS, HarmonyOS용 공통 코드 세트를 완성했습니다. 프로젝트에서 이전과 동일한 것을 구현해야 할 필요성을 만났습니다. Android 기본 텍스트가 최대 줄 수를 초과하면 끝 부분이 잘리고 확장/축소됩니다. 처음에는 익숙하지 않았기 때문에 처음에는 Stack을 사용하여 maxLines 및 Overflow를 동적으로 제어하고 오른쪽 하단에 마스크와 텍스트를 넣어 이를 구현했습니다. 나중에 일부 스크린폰에서는 부분적으로 당황스러운 상황이 발생한다는 것을 알았습니다. 의 텍스트가 가려지고 단어의 절반이 새어 나옵니다. 오늘 드디어 구현 계획을 최적화할 시간이 생겼습니다.
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는 긴 텍스트 콘텐츠를 표시하는 데 사용되는 맞춤 Flutter 위젯입니다. 텍스트 길이가 미리 설정된 최대 줄 수를 초과하면 텍스트가 축소되고 "확장" 링크가 표시됩니다. 클릭하면 텍스트가 완전히 확장되고 다시 클릭하면 텍스트가 축소됩니다.
StatefulWidget 및 _ExpandableTextState를 사용하여 텍스트의 확장/축소 상태를 관리합니다.
isExpanded 변수는 텍스트의 표시 상태를 제어합니다.
TextPainter 및 RichText 구성 요소를 사용하여 텍스트를 측정하고 렌더링합니다.
텍스트가 최대 줄 수를 초과하는 경우 텍스트를 계산하고 가로채서 텍스트가 접힌 상태에서 올바르게 표시되는지 확인하고 "확장" 링크를 추가합니다.
TapGestureRecognizer를 통해 클릭 이벤트 모니터링을 추가하여 "확장" 및 "접기" 기능을 구현합니다.
setState 메소드는 텍스트 표시 상태를 업데이트하는 데 사용됩니다.
다양한 화면 크기와 레이아웃 환경을 수용할 수 있는 사용 가능한 너비를 얻으려면 LayoutBuilder를 사용하세요.
checkOverflow 메서드는 텍스트가 설정된 최대 줄 수를 초과하는지 여부를 확인하는 데 사용됩니다.
maxLines, textStyle, linkTextExpand, linkTextCollapse, linkTextColor와 같은 구성 가능한 여러 매개변수를 제공하여 사용자가 텍스트의 모양과 동작을 사용자 정의할 수 있습니다.
ExpandableText(
text: "这是一段很长的文本,它将被折叠起来,只有在点击'展开'链接后才会完全显示。",
maxLines: 2,
textStyle: TextStyle(fontSize: 16, color: Colors.black),
linkTextExpand: " 展开",
linkTextCollapse: " 收起",
linkTextColor: Colors.blue,
);
ExpandableText를 사용할 때 텍스트의 접는 지점이 올바르게 계산되도록 충분한 컨텍스트 너비를 제공하는지 확인하십시오.
최상의 시각적 효과를 얻으려면 실제 요구 사항에 따라 사용자 정의 스타일 매개변수를 조정해야 합니다.