Flutter带前置点文本悬停优化:隐藏点下的橙色下划线
Flutter 带前置圆点文本悬停下划线动画问题解决
问题描述
用Flutter实现带前置圆点的文本悬停动画时,设置hasDot: true后橙色下划线会出现在圆点下方,需求是保留圆点的同时,让下划线仅在文本区域执行动画,隐藏圆点下方的线条。
解决方案
通过调整组件层级,将文本与下划线限制在独立的文本宽度容器内,并添加裁剪组件避免下划线溢出到圆点区域,修改后的代码如下:
import 'package:flutter/material.dart'; class MyText extends StatefulWidget { final String text; final TextStyle textStyle; final double width; final double underlineOffset; final bool hasDot; const MyText({ super.key, required this.text, required this.textStyle, required this.width, required this.underlineOffset, this.hasDot = false, }); @override State<MyText> createState() => _MyTextState(); } class _MyTextState extends State<MyText> with TickerProviderStateMixin { late AnimationController _colorAnimationController; late Animation _colorAnimation; late AnimationController _underlineAnimationController; late Animation _underlineAnimation; @override void initState() { _colorAnimationController = AnimationController( duration: const Duration(milliseconds: 250), vsync: this, )..addListener(() { setState(() {}); }); _colorAnimation = ColorTween( begin: Colors.black, end: Colors.orange, ).animate(_colorAnimationController); _underlineAnimationController = AnimationController( duration: const Duration(milliseconds: 500), vsync: this, )..addListener(() { if (_underlineAnimationController.isCompleted && _underlineAnimationController.value == 1) { _underlineAnimationController.reset(); } setState(() {}); }); _underlineAnimation = Tween(begin: -widget.width, end: widget.width) .animate(_underlineAnimationController); super.initState(); } @override Widget build(BuildContext context) { return MouseRegion( onEnter: (event) { _colorAnimationController.forward(); _underlineAnimationController.animateTo(0.5); }, onExit: (event) { _colorAnimationController.reverse(); _underlineAnimationController.animateTo(1); }, cursor: SystemMouseCursors.click, child: Container( alignment: Alignment.centerRight, width: widget.hasDot ? widget.width + 25 : widget.width, height: widget.underlineOffset + 2, child: Stack( clipBehavior: Clip.none, children: [ // 文本与下划线容器:限制在文本宽度内并裁剪溢出部分 Align( alignment: Alignment.centerRight, child: ClipRect( child: Container( width: widget.width, height: widget.underlineOffset + 2, child: Stack( children: [ // 文本 Text( widget.text, style: widget.textStyle.copyWith( color: _colorAnimation.value, ), ), // 悬停下划线动画 Positioned( top: widget.underlineOffset, left: _underlineAnimation.value, child: Container( width: widget.width, height: 1, color: Colors.orange, ), ) ], ), ), ), ), // 前置圆点 if (widget.hasDot) const Positioned( top: 9, left: -26, child: Icon( Icons.circle, color: Colors.black, size: 10, ), ), ], ), ), ); } }
修改说明
- 拆分组件层级:将文本和下划线独立封装到宽度为
widget.width的容器中,通过Align对齐到父容器右侧,让文本区域与圆点区域彻底分离。 - 添加裁剪组件:使用
ClipRect裁剪下划线超出文本宽度的部分,确保动画过程中线条仅显示在文本下方,不会延伸到圆点区域。 - 保留原有动画逻辑:颜色切换和下划线滑动的动画逻辑保持不变,仅调整了组件的布局结构。
内容的提问来源于stack exchange,提问作者Furiy
相关产品推荐
相关产品推荐

