最近碰到一个需要须要实现一个矩形,矩形边框为渐变色,并且要求渐变色一直滚动向前,如下图所示
次要思路参考自这篇文章 另外还有来自 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;} }