【问题标题】:Arc gradients in Flutter?Flutter 中的弧形渐变?
【发布时间】:2018-05-08 04:01:06
【问题描述】:

我有一个Paint 对象,我正在尝试使用它来使用canvas.drawArc 绘制弧形渐变,但这样做的唯一方法(至少根据我的研究)是使用Shader ,但是要从Gradient 对象中获取Shader,您必须使用Gradient.createShader(Rect rect),它需要一个矩形。我的问题是,有没有办法为 Arc 而不是 Rectangle 创建着色器?以下是我目前的参考资料:

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);

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    我的 SweepGradient 版本。

    完整示例:

    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;
    }
    

    结果:

    【讨论】:

    • 即使进度只是部分,如何使渐变成为全色谱?例如,如果进度只有 0.2,我实际上希望看到从红色到蓝色的整个扫描过程。不仅仅是蓝色部分
    【解决方案2】:

    您需要的 Rectangle 实际上是一个正方形,您正在绘制的圆适合该正方形。弧线只是那圈扫过这么多弧度的馅饼。使用Rect.fromCircle 创建这个正方形,使用中心和半径。然后在创建渐变和绘制弧线时使用这个正方形。

    这是一个例子

    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(),
        ),
      );
    }
    

    【讨论】:

    • 有什么方法可以做同样的事情,但要使用PaintingStyle.stroke 绘制吗?为Paint.style 设置它会完全停止绘制弧线。
    • 我不太清楚你的意思。使用PaintingStyle.stroke,您只需使用渐变绘制轮廓。如果你想用一种颜色绘制轮廓并用渐变填充它,请绘制两次圆弧。第一次如上图;第二次使用新的 Paint 设置样式、strokeWidth 和颜色。
    • 好的,抱歉;我画的弧不够大,它就在那里,我只是看不到它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 2021-01-23
    相关资源
    最近更新 更多