You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何实现文本删除线动画效果?

在Flutter中实现待办任务的删除线动画效果

要实现删除线从左到右平滑划过的动画效果,你可以通过自定义带动画的文本组件来实现,以下是具体方案:

实现步骤

1. 自定义带动画删除线的TaskText组件

创建一个StatefulWidget,结合动画控制器和自定义裁剪器,实现删除线的渐进式显示/隐藏:

class TaskText extends StatefulWidget {
  final String title;
  final bool isDone;
  final TextStyle style;

  const TaskText({
    super.key,
    required this.title,
    required this.isDone,
    required this.style,
  });

  @override
  State<TaskText> createState() => _TaskTextState();
}

class _TaskTextState extends State<TaskText> with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _lineAnimation;
  late Animation<Color?> _colorAnimation;

  @override
  void initState() {
    super.initState();
    // 初始化动画控制器,设置动画时长
    _animationController = AnimationController(
      duration: const Duration(milliseconds: 500),
      vsync: this,
    );
    // 删除线进度动画:从0到1
    _lineAnimation = Tween<double>(begin: 0, end: 1).animate(
      CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
    );
    // 文本颜色渐变动画:从原始色到灰色
    _colorAnimation = ColorTween(
      begin: widget.style.color,
      end: Colors.grey,
    ).animate(_animationController);

    // 初始状态为已完成时,直接完成动画
    if (widget.isDone) {
      _animationController.forward();
    }
  }

  @override
  void didUpdateWidget(covariant TaskText oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 监听isDone状态变化,触发动画
    if (widget.isDone != oldWidget.isDone) {
      widget.isDone ? _animationController.forward() : _animationController.reverse();
    }
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        // 显示原始文本,颜色随动画渐变
        Text(
          widget.title,
          overflow: TextOverflow.ellipsis,
          style: widget.style.copyWith(
            decoration: TextDecoration.none,
            color: _colorAnimation.value,
          ),
        ),
        // 动画删除线:通过裁剪容器实现渐进显示
        AnimatedBuilder(
          animation: _lineAnimation,
          builder: (context, child) {
            return ClipPath(
              clipper: _LineClipper(progress: _lineAnimation.value),
              child: child,
            );
          },
          child: Container(
            height: 2,
            // 调整删除线的垂直位置,适配字体大小
            margin: EdgeInsets.only(top: widget.style.fontSize! * 0.7),
            color: Colors.grey,
          ),
        ),
      ],
    );
  }
}

// 自定义裁剪器,根据动画进度控制删除线的显示范围
class _LineClipper extends CustomClipper<Path> {
  final double progress;

  _LineClipper({required this.progress});

  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(size.width * progress, 0);
    path.lineTo(size.width * progress, size.height);
    path.lineTo(0, size.height);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(covariant _LineClipper oldClipper) {
    return progress != oldClipper.progress;
  }
}

2. 替换原有Text组件

将你原来的Text.rich替换为自定义的TaskText:

TaskText(
  title: task.title,
  isDone: task.isDone,
  style: const TextStyle(
    fontFamily: 'Helvatica_lite',
    fontWeight: FontWeight.bold,
    fontSize: 15,
    color: Colors.black,
  ),
);

效果说明

  • 当task.isDone变为true时,删除线会从左到右平滑划过,同时文本颜色逐渐变为灰色
  • 当task.isDone变为false时,删除线会从右到左隐藏,文本颜色恢复为黑色
  • 动画时长可通过修改AnimationController的duration参数调整

内容的提问来源于stack exchange,提问作者mishalhaneef

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 16:20:41