如何在Flutter中实现类似iPhone关机按钮的文字滑动变色动画?
实现Flutter文字滑过变色动画(类似iPhone关机按钮效果)
要实现白色图层滑过文字、逐步将黑色文字转为白色再恢复的循环动画,不能直接用AnimationController控制文字颜色(这种方式会一次性切换颜色)。我们可以通过双层文字+裁剪动画的方式模拟滑过效果,具体实现如下:
核心思路
用Stack堆叠两个相同的文字:
- 底层为黑色文字(初始显示状态)
- 上层为白色文字,通过
ClipRect结合动画控制其显示区域,让白色文字从左到右(或指定方向)逐步覆盖底层黑色文字,再反向隐藏,实现“滑过”的视觉效果
完整代码示例
import 'package:flutter/material.dart'; class SlideTextAnimation extends StatefulWidget { final String text; final TextStyle style; final Duration duration; const SlideTextAnimation({ super.key, required this.text, required this.style, this.duration = const Duration(seconds: 2), }); @override State<SlideTextAnimation> createState() => _SlideTextAnimationState(); } class _SlideTextAnimationState extends State<SlideTextAnimation> with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation<double> _animation; @override void initState() { super.initState(); // 初始化动画控制器,设置循环反向动画 _controller = AnimationController( vsync: this, duration: widget.duration, )..repeat(reverse: true); // 创建从0到1的动画值,用于控制裁剪区域 _animation = Tween<double>(begin: 0, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Stack( alignment: Alignment.center, children: [ // 底层黑色文字 Text(widget.text, style: widget.style.copyWith(color: Colors.black)), // 上层白色文字,通过裁剪控制显示区域 AnimatedBuilder( animation: _animation, builder: (context, child) { return ClipRect( // 自定义裁剪器,根据动画值控制显示宽度 clipper: _SlideClipper(_animation.value), child: child, ); }, child: Text(widget.text, style: widget.style.copyWith(color: Colors.white)), ), ], ); } } // 自定义裁剪器:根据动画值裁剪出从左到右的区域 class _SlideClipper extends CustomClipper<Rect> { final double offset; _SlideClipper(this.offset); @override Rect getClip(Size size) { // offset从0到1时,裁剪区域从左到右扩展;从1到0时,区域从右到左收缩 return Rect.fromLTRB(0, 0, size.width * offset, size.height); } @override bool shouldReclip(_SlideClipper oldClipper) { return oldClipper.offset != offset; } } // 使用示例 void main() { runApp(const MaterialApp( home: Scaffold( backgroundColor: Colors.grey.shade900, body: Center( child: SlideTextAnimation( text: "滑动关机", style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ), ), ), )); }
关键细节说明
- 动画控制器配置:通过
repeat(reverse: true)让动画自动循环并反向播放,实现“变白→变黑”的往复效果 - 裁剪器逻辑:
_SlideClipper根据动画值动态调整裁剪区域的宽度,当offset从0到1时,白色文字从左到右逐步显示;从1到0时,白色文字逐步隐藏 - 样式复用:通过
copyWith复用传入的文字样式,仅修改颜色,保证两层文字的大小、字体完全一致
如果需要改变滑过方向(比如从右到左、从上到下),只需修改_SlideClipper的getClip方法即可:
- 从右到左:
Rect.fromLTRB(size.width * (1 - offset), 0, size.width, size.height) - 从上到下:
Rect.fromLTRB(0, 0, size.width, size.height * offset)
内容的提问来源于stack exchange,提问作者Adeeb K
相关产品推荐
相关产品推荐

