介绍
文字跑马灯组件可以定义文字移动方向 时长等设置
![](https://img.haomeiwen.com/i27902463/d5516bcff70353ea.gif)
代码演示
基础用法
HcMarquee(
content:
"青年的命运,从来都同时代紧密相连。新民主主义革命时期,青春是漫漫长征路上那一声坚定的“跟着走”,走向柳暗花明的胜利之路;”
修改滚动时长
HcMarquee(
duration: Duration(milliseconds: 60000),
content:
"青年的命运,从来都同时代紧密相连。新民主主义革命时期,青春是漫漫长征路上那一声坚定的“跟着走”,走向柳暗花明的胜利之路;",
),
修改滚动方向
如果纵向传入 content 则按照长度自动截断成组
HcMarquee(
scrollDirection: Axis.vertical,
content:
"青年的命运,从来都同时代紧密相连。新民主主义革命时期,青春是漫漫长征路上那一声坚定的“跟着走”,走向柳暗花明的胜利之路;",
自定义滚动组
HcMarquee(
scrollDirection: Axis.vertical,
contentList: [
"君不见黄河之水天上来,奔流到海不复回。",
"君不见高堂明镜悲白发,朝如青丝暮成雪。",
" 人生得意须尽欢,莫使金樽空对月。",
" 天生我材必有用,千金散尽还复来。",
" 烹羊宰牛且为乐,会须一饮三百杯。",
" 岑夫子,丹丘生,将进酒,杯莫停。",
"与君歌一曲,请君为我倾耳听。",
" 钟鼓馔玉不足贵,但愿长醉不复醒。",
" 古来圣贤皆寂寞,惟有饮者留其名。",
"陈王昔时宴平乐,斗酒十千恣欢谑。",
"主人何为言少钱,径须沽取对君酌。",
"五花马、千金裘,呼儿将出换美酒,与尔同销万古愁。"
],
),
不允许自动滚动
HcMarquee(
enableScroll: false,
content:
"青年的命运,从来都同时代紧密相连。新民主主义革命时期,青春是漫漫长征路上那一声坚定的“跟着走”,走向柳暗花明的胜利之路;"),
不允许自动滚动也不允许手动滑动
HcMarquee(
enableScroll: false,
physics: NeverScrollableScrollPhysics(),
content:
"青年的命运,从来都同时代紧密相连。新民主主义革命时期,青春是漫漫长征路上那一声坚定的“跟着走”,走向柳暗花明的胜利之路;"),
文字不满一屏也强制滚动
HcMarquee(
content: "青年的命运,从来都同时代紧密相连。",
forceScroll: true,
),
API
props
参数 | 说明 | 类型 | 默认值 | 是否必填 |
---|---|---|---|---|
enableScroll | 是否允许滚动 | bool | true | true |
forceScroll | 横向不满一屏时是否强制滚动 | bool | true | true |
duration | 滚动时长 | int | 20000 | true |
scrollDirection | 滚动方向 | Axis | Axis.horizontal | true |
content | 内容文字 | String | "" | false |
contentList | 纵向滚动时 文字组 | List<String>? | - | false |
textStyle | 文字样式 | TextStyle | - | false |
physics | 手动滚动时样式 | ScrollPhysics | - | false |
overflow | 纵向滚动文字组超出样式 | TextOverflow | ellipsis | false |
textAlign | 纵向滚动文字对齐方向 | TextAlign | TextAlign.start | false |
项目源码
String _defaultText = "未设置滚动文字!!!";
class HcMarquee extends StatefulWidget {
//滚动文字
final String? content;
//纵向滚动的文字组
final List<String>? contentList;
//滚动方向
final Axis scrollDirection;
//滚动总时长
final Duration duration;
//文字样式
final TextStyle textStyle;
//是否允许滚动
final bool enableScroll;
//不满全屏时是否强制滚动 仅用在横向
final bool forceScroll;
// 滚动效果 仅用在不自动滑动时
final ScrollPhysics? physics;
//仅用在自定义文字组 纵向滑动时
final TextOverflow overflow;
//仅用在纵向滑动时文字对齐方式
final TextAlign textAlign;
const HcMarquee({
Key? key,
this.content,
this.contentList,
this.scrollDirection = Axis.horizontal,
this.duration = const Duration(milliseconds: 10000),
this.textStyle = const TextStyle(color: Colors.black, fontSize: 16),
this.enableScroll = true,
this.forceScroll = false,
this.physics,
this.overflow = TextOverflow.ellipsis,
this.textAlign = TextAlign.start,
}) : super(key: key);
@override
State<HcMarquee> createState() => _HcMarqueeState();
}
class _HcMarqueeState extends State<HcMarquee>
with SingleTickerProviderStateMixin {
//获取组件最大宽度与高度
Size _viewSize = const Size(0, 0);
//动画的控制器
late AnimationController _animationController;
//动画
late Animation<Offset> _animation;
//滚动控制器
final ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: widget.duration);
_animation = Tween(begin: const Offset(0, 0), end: const Offset(1, 0))
.animate(_animationController);
_animation.addListener(() {
//如果有子组件
if (_scrollController.hasClients) {
if (_scrollController.position.hasContentDimensions) {
if (widget.scrollDirection == Axis.horizontal) {
//前后两端内容+空白区域
double fullLength = _scrollController.position.maxScrollExtent +
2 * _viewSize.width;
_scrollController
.jumpTo(_animation.value.dx * fullLength - _viewSize.width);
} else {
_scrollController.jumpTo(_animation.value.dx *
_scrollController.position.maxScrollExtent);
}
}
}
});
}
@override
void dispose() {
_scrollController.dispose();
_animationController.dispose();
super.dispose();
}
@override
void didUpdateWidget(covariant HcMarquee oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
if (oldWidget != widget) {
_animationController.duration = widget.duration;
}
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, size) {
_viewSize = Size(size.maxWidth, size.maxHeight);
String content = widget.content ?? _defaultText;
List<String> contentList = widget.contentList ?? [];
Widget child = Container();
if (widget.scrollDirection == Axis.horizontal) {
child = _buildHorizontalView(contentList, content, size);
} else {
child = _buildVerticalView(contentList, content, size);
}
return child;
});
}
//构建纵向列表
Widget _buildVerticalView(
List<String> contentList, String content, BoxConstraints size) {
if (widget.contentList != null && widget.contentList!.isNotEmpty) {
contentList = widget.contentList!;
} else {
contentList = [];
while (content.isNotEmpty) {
TextPainter painter = HcStringUtil.getTextInfo(
content, widget.textStyle,
maxLines: 1, width: _viewSize.width);
int maxIndex =
painter.getPositionForOffset(Offset(_viewSize.width, 0)).offset;
contentList.add(content.substring(0, min((maxIndex), content.length)));
content = content.substring(min(maxIndex, content.length));
}
}
TextPainter painter =
HcStringUtil.getTextInfo(_defaultText, widget.textStyle);
//如果行数大于一滚动
if (contentList.length > 1 && widget.enableScroll) {
_animationController.repeat();
} else {
_animationController.stop();
}
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: _viewSize.width,
minHeight: painter.height,
maxHeight: painter.height),
child: ListView.builder(
physics: widget.physics,
itemBuilder: (context, index) => Text(
contentList[index],
textAlign: widget.textAlign,
style: widget.textStyle,
maxLines: 1,
overflow: widget.overflow,
),
shrinkWrap: true,
controller: _scrollController,
itemCount: contentList.length,
scrollDirection: Axis.vertical),
);
}
//构建横向滚动组件
SingleChildScrollView _buildHorizontalView(
List<String> contentList, String content, BoxConstraints size) {
if (widget.content != null) {
content = widget.content!;
} else if (widget.contentList != null) {
content = contentList.join("");
}
TextPainter painter = HcStringUtil.getTextInfo(content, widget.textStyle,
width: _viewSize.width, maxLines: 1);
if (widget.enableScroll &&
(!painter.didExceedMaxLines && widget.forceScroll ||
painter.didExceedMaxLines)) {
_animationController.repeat();
} else {
_animationController.stop();
}
return SingleChildScrollView(
controller: _scrollController,
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: _viewSize.width),
child: Text(
content,
style: widget.textStyle,
)),
);
}
}
/// 获取文字信息
static TextPainter getTextInfo(String text, TextStyle style,
{int maxLines = 2 ^ 23,
double width = double.infinity,
String? ellipsis,
textDirection = TextDirection.ltr}) {
TextSpan span = TextSpan(text: text, style: style);
return TextPainter(
text: span,
maxLines: maxLines,
ellipsis: ellipsis,
textDirection: textDirection,
)..layout(maxWidth: width);
}
网友评论