title: What is the correct animation to change the color of a CustomPainter in Flutter
body: <p>In my flutter application I want to animate the color change (the color is a gradient) of two elements that inherit from a custom painter, this happens when a button is clicked.</p>
  <p>My problem is that I can't find how to do it, since I understand that to animate an element a Tween is needed.</p>
  <p>I cannot find a Tween that is correct for my case, since the color change is done in the CustomPainter conditionally.</p>
  <p>The TweenColor class works, however I can't integrate it with a gradient and this doesn't work for me.</p>
  <p>This effect is the one I want:</p>
  <p>https://vimeo.com/578534813/e0f2d4ed73</p>
  <p>This is what I have without using the Tween Color, it is fine, however, it is not the animated effect that I want.</p>
  <p>https://vimeo.com/578538292/6e63a51060</p>
  <p>As you can see, it is close to what is required, but it is not.</p>
  <p>Thanks for your help, I leave the code.</p>
  <blockquote>
  <p>ScreenClass</p>
  </blockquote>
  <pre><code>class AuthScreen extends StatefulWidget {
  @override
  _AuthScreenState createState() =&gt; _AuthScreenState();
   }
  
   class _AuthScreenState extends State&lt;AuthScreen&gt; with SingleTickerProviderStateMixin 
   {
   late AnimationController controller;
   late Animation&lt;double&gt; opacity;
  
  
   @override
   void initState() {
  
   controller = new AnimationController(vsync: this,duration: Duration(seconds:2 ));
   opacity = Tween(begin: 0.1 ,end: 1.0).animate(controller);
  
   super.initState();
  }
  
   @override
   void dispose() { 
   controller.dispose();
   super.dispose();
  }
  
  
  
   @override
   Widget build(BuildContext context) {
    controller.forward();
  
   final authProvider = Provider.of&lt;AuthProvider&gt;(context,listen: false);
  
  
   return Scaffold(
    body: Stack(
      children: [
        Container(
         width: double.infinity,
         height: double.infinity,
         child: AnimatedBuilder(
           animation: controller,
           builder: (_,Widget? child){
             return Opacity(
               opacity: opacity.value,
               child: CustomPaint(
                 painter: BackgroundPainter(provider:authProvider),
               ),
             );
           },
         ),
        ),
        Center(
          child: MaterialButton(
            onPressed: (){
                controller.reset();
                controller.forward();
  
                authProvider.flag = !authProvider.flag;
  
                
            },
            shape: RoundedRectangleBorder(),
            elevation: 12,
            color: Colors.white,
            child: Text('Ingresar'),
          ),
        ),
        
        ])
  );
  }
   }
  </code></pre>
  <blockquote>
  <p>ProviderClass</p>
  </blockquote>
  <pre><code>class AuthProvider extends ChangeNotifier {
  bool _flag = false;
  
  bool get flag {
  print(_flag);
  return this._flag;
  }
  
   set flag(bool state) =&gt; this._flag = state; 
  
  
  }
  </code></pre>
  <blockquote>
  <p>CustomPaintClass</p>
  </blockquote>
  <pre><code>
  class BackgroundPainter extends CustomPainter {
    
    AuthProvider provider;
  
   BackgroundPainter({required this.provider});
  
    final Gradient redColor = new LinearGradient(colors: &lt;Color&gt;[
      Colors.white12,
      Color(0xffF7A2A3),
    ]);
  
    final Gradient blueColor = new LinearGradient(colors: &lt;Color&gt;[
      Colors.white12,
      Color(0xff74BDD7),
    ]);
  
  
    @override
    void paint(Canvas canvas, Size size) {
          
      final Rect rect = Rect.fromCircle(
          center: Offset(55.0, 155.0), 
          radius: 180);
  
      /**
       * *Header*
       */
      
      Gradient color ;
  
      if(!provider.flag)
      color = redColor;
      else
      color = blueColor;
  
      final paint = new Paint()..shader = color.createShader(rect);
  
      paint.style = PaintingStyle.fill; // .fill .stroke
      paint.strokeWidth = 20;
  
      final path = new Path();
  
      path.moveTo(size.width, 0);
      path.lineTo(size.width, size.height * 0.20);
  
      path.quadraticBezierTo(
          size.width * 0.95, size.height * 0.05, 0, size.height * 0.06);
      path.lineTo(0, 0);
  
      canvas.drawPath(path, paint);
  
  
  
      final Rect rect2 = Rect.fromCircle(
          center: Offset(55.0, 155.0), // x = horizontal y  = vertical
          radius: 180);
  
  
  
      /**
       * *Footer*
       */
  
      Gradient color2 ;
  
  
      if(!provider.flag)
      color2 = blueColor;
      else
      color2 = redColor;
  
      final paint2 = new Paint()..shader = color2.createShader(rect2);
  
      paint2.style = PaintingStyle.fill;
      paint2.strokeWidth = 30;
  
      final path2 = new Path();
  
      path2.moveTo(0, size.height);
      path2.lineTo(0, size.height * 0.80);
      path2.quadraticBezierTo(
          size.width * 0.05, size.height * 0.95, size.width, size.height * 0.94);
  
      path2.lineTo(size.width, size.height);
  
      canvas.drawPath(path2, paint2);
    }
  
    @override
    bool shouldRepaint(CustomPainter oldDelegate) {
      return true;
    }
  }
  
  </code></pre>