Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Arc gradients in Flutter?

Tags:

flutter

dart

I have a Paint object and I'm trying to use it to paint an Arc Gradient using canvas.drawArc, but the only way to do this (at least according to my research) is to use a Shader, but to get a Shader from a Gradient object, you have to use Gradient.createShader(Rect rect), which takes a rectangle. My question is, is there any way to create a shader for an Arc and not a Rectangle? Here's what I have so far for reference:

Paint paint = new Paint()
  ..color = bgColor
  ..strokeCap = StrokeCap.round
  ..strokeWidth = 3.0
  ..style = PaintingStyle.stroke
  ..shader = new Gradient.radial(size.width / 2.0, size.height / 2.0, size.height / 3.0, Colors.transparent, timerColor, TileMode.mirror).createShader(/* I don't have a rect object */);


canvas.drawArc(..., paint);
like image 546
PavelF Avatar asked May 08 '18 04:05

PavelF


People also ask

How many types of gradient are there in Flutter?

Flutter offers 3 types of gradients: Linear Gradient. Radial Gradient. Sweep Gradient.

How do you draw an arc in Flutter?

Drawing the arcs Luckily, the canvas also allows drawing an arc on the canvas. To draw an arc, I have to create a rectangle from the circle, the starting angle, the length of the arc, and a paint. If this ArcPainter is wrapped in the CustomPaint Widget, these are no regular arcs.


1 Answers

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:

like image 177
nagoya0 Avatar answered Oct 02 '22 22:10

nagoya0