最近碰到一个需求需要实现一个矩形,矩形边框为渐变色,并且要求渐变色不断滚动向前,如下图所示
主要思路参考自这篇文章 另外还有来自 chatgpt 的回答,实现效果如上图所示效果
具体实现思路
用
CustomPainter
实现一个渐变矩形边框void paint(Canvas canvas, Size size) { // 创建一个矩形区域 final rect = Rect.fromLTWH(0, 0, 96, 38); final paint = Paint() ..shader = LinearGradient( // 渐变色值 colors: const [Color.yellow, Colors.green], // 此处是实现动画的关键 => 动态传入角度来实现动画 transform: GradientRotation(animation * 2 * pi), // 创建一个线性渐变着色器对象并将其应用于矩形形状的填充 ).createShader(rect) ..style = PaintingStyle.stroke // 边框宽度为 2 注意边框宽度是在矩形外边,所以这个矩形的宽高就变为 100*42 ..strokeWidth = 2; // 实现圆角矩形 final rRect = RRect.fromRectAndRadius(rect, const Radius.circular(8)); canvas.drawRRect(rRect, paint); // 另外也可实现直角矩形/圆形 // 画直角矩形 canvas.drawRect(rect, paint); // 画圆形 参数:圆心坐标, 半径 canvas.drawCircle(Offset(48, 20), 50, paint); }
动画实现借助显式动画
AnimationController
和AnimationBuilder
,具体写法看下方完整代码完整代码
核心绘图代码
import 'dart:math'; import 'package:flutter/material.dart'; class GradientBound extends StatefulWidget { // 矩形 长、宽、边框宽度,其中长、宽已包含边框宽度 final double width; final double height; final double border; final Widget child; const GradientBound({ super.key, required this.width, required this.height, required this.border, required this.child, }); @override State<GradientBound> createState() => _GradientBoundState(); } class _GradientBoundState extends State<GradientBound> with SingleTickerProviderStateMixin { late Animation<double> animation; late AnimationController controller; @override void initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this, ); animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation( parent: controller, curve: Curves.linear, )); controller.repeat(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: animation, builder: (BuildContext context, Widget? child) { return CustomPaint( // 创建 painter painter: GradientBoundPainter( colors: const [Color.yellow, Colors.green], animation: animation.value, width: widget.width, height: widget.height, border: widget.border, ), // child 内容铺满容器并居中 child: Container( alignment: Alignment.center, width: widget.width, height: widget.height, color: Colors.transparent, child: widget.child, ), ); }); } @override void dispose() { controller.dispose(); super.dispose(); } } // 渐变边框核心绘图逻辑 class GradientBoundPainter extends CustomPainter { final List<Color> colors; final double animation; final double width; final double height; final double border; const GradientBoundPainter({ Key? key, required this.colors, required this.animation, required this.width, required this.height, required this.border, }); @override void paint(Canvas canvas, Size size) { final rect = Rect.fromLTWH(0, 0, width, height); final paint = Paint() ..shader = LinearGradient( colors: colors, transform: GradientRotation(animation * 2 * pi), ).createShader(rect) ..style = PaintingStyle.stroke ..strokeWidth = border; final rRect = RRect.fromRectAndRadius(rect, const Radius.circular(8)); canvas.drawRRect(rRect, paint); } @override bool shouldRepaint(covariant GradientBoundPainter oldDelegate) { return oldDelegate.colors != colors || oldDelegate.animation != animation; } }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。