最近碰到一个需要须要实现一个矩形,矩形边框为渐变色,并且要求渐变色一直滚动向前,如下图所示

次要思路参考自这篇文章 另外还有来自 chatgpt 的答复,实现成果如上图所示成果

具体实现思路

  1. 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);  }
  2. 动画实现借助显式动画 AnimationControllerAnimationBuilder,具体写法看下方残缺代码

    残缺代码

  3. 外围绘图代码

    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;  }}