关于flutter:flutter-实现渐变动画矩形边框

32次阅读

共计 2842 个字符,预计需要花费 8 分钟才能阅读完成。

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

次要思路参考自这篇文章 另外还有来自 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;}
    }
    

正文完
 0