Arc gradients in Flutter?

The Rectangle that you need is actually a square into which the circle that you are drawing would fit. The arc is just a slice of pie from that circle swept through so many radians. Create this square using Rect.fromCircle, using the centre and radius. You then use this square when creating the gradient and drawing the arc.

Here's an example

import 'dart:math';

import 'package:flutter/material.dart';

class X1Painter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    // create a bounding square, based on the centre and radius of the arc
    Rect rect = new Rect.fromCircle(
      center: new Offset(165.0, 55.0),
      radius: 180.0,
    );

    // a fancy rainbow gradient
    final Gradient gradient = new RadialGradient(
      colors: <Color>[
        Colors.green.withOpacity(1.0),
        Colors.green.withOpacity(0.3),
        Colors.yellow.withOpacity(0.2),
        Colors.red.withOpacity(0.1),
        Colors.red.withOpacity(0.0),
      ],
      stops: [
        0.0,
        0.5,
        0.7,
        0.9,
        1.0,
      ],
    );

    // create the Shader from the gradient and the bounding square
    final Paint paint = new Paint()..shader = gradient.createShader(rect);

    // and draw an arc
    canvas.drawArc(rect, pi / 4, pi * 3 / 4, true, paint);
  }

  @override
  bool shouldRepaint(X1Painter oldDelegate) {
    return true;
  }
}

class X1Demo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: const Text('Arcs etc')),
      body: new CustomPaint(
        painter: new X1Painter(),
      ),
    );
  }
}

void main() {
  runApp(
    new MaterialApp(
      theme: new ThemeData.dark(),
      home: new X1Demo(),
    ),
  );
}

My SweepGradient version.

Complete example:

import 'dart:math' as math;

import 'package:flutter/material.dart';

class GradientArcPainterDemo extends StatefulWidget {
  const GradientArcPainterDemo({
    Key key,
  }) : super(key: key);

  @override
  GradientArcPainterDemoState createState() => GradientArcPainterDemoState();
}

class GradientArcPainterDemoState extends State<GradientArcPainterDemo> {
  double _progress = 0.9;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(title: const Text('GradientArcPainter Demo')),
      body: GestureDetector(
        onTap: () {
          setState(() {
            _progress += 0.1;
          });
        },
        child: Center(
          child: SizedBox(
            width: 200.0,
            height: 200.0,
            child: CustomPaint(
              painter: GradientArcPainter(
                progress: _progress,
                startColor: Colors.blue,
                endColor: Colors.red,
                width: 8.0,
              ),
              child: Center(child: Text('$_progress')),
            ),
          ),
        ),
      ),
    );
  }
}

class GradientArcPainter extends CustomPainter {
  const GradientArcPainter({
    @required this.progress,
    @required this.startColor,
    @required this.endColor,
    @required this.width,
  })  : assert(progress != null),
        assert(startColor != null),
        assert(endColor != null),
        assert(width != null),
        super();

  final double progress;
  final Color startColor;
  final Color endColor;
  final double width;

  @override
  void paint(Canvas canvas, Size size) {
    final rect = new Rect.fromLTWH(0.0, 0.0, size.width, size.height);
    final gradient = new SweepGradient(
      startAngle: 3 * math.pi / 2,
      endAngle: 7 * math.pi / 2,
      tileMode: TileMode.repeated,
      colors: [startColor, endColor],
    );

    final paint = new Paint()
      ..shader = gradient.createShader(rect)
      ..strokeCap = StrokeCap.butt  // StrokeCap.round is not recommended.
      ..style = PaintingStyle.stroke
      ..strokeWidth = width;
    final center = new Offset(size.width / 2, size.height / 2);
    final radius = math.min(size.width / 2, size.height / 2) - (width / 2);
    final startAngle = -math.pi / 2;
    final sweepAngle = 2 * math.pi * progress;
    canvas.drawArc(new Rect.fromCircle(center: center, radius: radius),
        startAngle, sweepAngle, false, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}

Result:

Tags:

Dart

Flutter