Flutter中如何给Container实现无限循环的动画边框效果?
实现方案
你需要配合AnimationController做无限动画,结合PathMetric动态截取正方形边框的路径片段,就能实现循环滚动的动画边框效果,完整实现代码如下:
1. 主页面Widget代码(包含动画控制器)
import 'package:flutter/material.dart'; class AnimatedBorderContainer extends StatefulWidget { final double size; final Color borderColor; final double strokeWidth; final Duration duration; const AnimatedBorderContainer({ super.key, this.size = 200, this.borderColor = Colors.blue, this.strokeWidth = 3, this.duration = const Duration(seconds: 2), }); @override State<AnimatedBorderContainer> createState() => _AnimatedBorderContainerState(); } class _AnimatedBorderContainerState extends State<AnimatedBorderContainer> with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation<double> _animation; @override void initState() { super.initState(); _controller = AnimationController(vsync: this, duration: widget.duration); _animation = Tween<double>(begin: 0, end: 1).animate(_controller); // 设置无限循环播放 _controller.repeat(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return CustomPaint( size: Size(widget.size, widget.size), painter: RadialPainter( progress: _animation.value, color: widget.borderColor, strokeWidth: widget.strokeWidth, strokeCap: StrokeCap.round, paintingStyle: PaintingStyle.stroke, // 这里设置边框显示的片段长度,0.2代表总周长的20% segmentLength: 0.2, ), ); }, ); } }
2. 修改后的RadialPainter代码
class RadialPainter extends CustomPainter { final Color color; final StrokeCap strokeCap; final PaintingStyle paintingStyle; final double strokeWidth; final double progress; final double segmentLength; RadialPainter({ required this.color, required this.strokeWidth, required this.strokeCap, required this.paintingStyle, required this.progress, required this.segmentLength, }); @override void paint(Canvas canvas, Size size) { Paint paint = Paint() ..strokeWidth = strokeWidth ..color = color ..style = paintingStyle ..strokeCap = strokeCap; // 构建完整的正方形路径 Path path = Path() ..moveTo(0, 0) ..lineTo(size.width, 0) ..lineTo(size.width, size.height) ..lineTo(0, size.height) ..close(); // 计算路径总长度 PathMetric pathMetric = path.computeMetrics().first; double totalLength = pathMetric.length; // 计算当前片段的起止点 double start = progress * totalLength; double end = start + segmentLength * totalLength; Path segmentPath; if (end <= totalLength) { segmentPath = pathMetric.extractPath(start, end); } else { // 片段跨路径首尾时,拼接两部分路径 segmentPath = pathMetric.extractPath(start, totalLength); segmentPath.addPath(pathMetric.extractPath(0, end % totalLength), Offset.zero); } canvas.drawPath(segmentPath, paint); } @override bool shouldRepaint(RadialPainter oldDelegate) { return oldDelegate.progress != progress; } }
使用方法
直接在需要的地方引入AnimatedBorderContainer即可,可自定义尺寸、边框颜色、动画速度、线条粗细等参数:
AnimatedBorderContainer( size: 300, borderColor: Colors.green, strokeWidth: 4, duration: Duration(seconds: 3), )
如果需要给边框内部加内容,直接在CustomPaint的child参数里传入你的Container即可。
内容的提问来源于stack exchange,提问作者Mariam Younes
相关产品推荐
相关产品推荐

