Flutter 半饼图与 fl_chart

问题描述 投票:0回答:1

我想在 Flutter 中向我的应用程序添加一个饼图,它只是一个半圆/半甜甜圈或任何你所说的东西。 它应该看起来像这样:

enter image description here

但目前看起来像这样,我不知道是否有办法解决它:

enter image description here

主要:

body: Center(
      //mainAxisAlignment: MainAxisAlignment.center,
      child: Column(
        children: [
          Stack(
            children: [
              const Align(
                alignment: Alignment.topCenter,
                child: Padding(
                  padding: EdgeInsets.only(top: 5.0),
                  child: Text(
                    "Status",
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 25,
                    ),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.topRight,
                child: Padding(
                  padding: const EdgeInsets.only(right: 8, top: 5),
                  child: CircleAvatar(
                    radius: 17,
                    backgroundColor: Colors.lightBlue,
                    child: IconButton(
                        tooltip:
                            "Show tooltip",
                        onPressed: () {},
                        icon: const Icon(
                          Icons.question_mark,
                          color: Colors.white,
                          size: 18,
                        )),
                  ),
                ),
              ),
            ],
          ),
          Container(
              width: 300.0,
              height: 300.0,
              //color: const Color.fromRGBO(72, 75, 80, 1),
              color: const Color.fromRGBO(72, 75, 80, 1),
              child: Stack(
                alignment: Alignment.center,
                children: [
                  // icon, svg, image

                  (isSwitched)
                      ? Padding(
                          //padding: EdgeInsets.only(
                          // right: 8.0, left: 8.0, bottom: 75),
                          padding: EdgeInsets.all(8),
                          child: Text(
                            "Moderate",
                            style: TextStyle(
                              color: Colors.white,
                              fontSize: 23,
                            ),
                          ),
                        )
                      : Padding(
                          //padding: EdgeInsets.only(
                          // right: 8.0, left: 8.0, bottom: 75),
                          padding: EdgeInsets.all(8),
                          child: Text(
                            "Excellent",
                            style: TextStyle(
                              color: Colors.white,
                              fontSize: 23,
                            ),
                          ),
                        ),
                  (isSwitched) ? MyPieChartYellow() : MyPieChart(),
                ],
              )),

饼图:

import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';

class MyPieChart extends StatelessWidget {
  const MyPieChart({super.key});

  @override
  Widget build(BuildContext context) {
    return PieChart(
        swapAnimationDuration: const Duration(milliseconds: 750),
        swapAnimationCurve: Curves.easeInQuint,
        PieChartData(centerSpaceRadius: 85.0, sections: [
          PieChartSectionData(
            value: 0,
            color: Colors.red,
            showTitle: false,
            radius: 42,
          ),
          PieChartSectionData(
            value: 0,
            color: Colors.yellow,
            showTitle: false,
            radius: 42,
          ),
          PieChartSectionData(
            value: 10,
            color: Colors.green,
            showTitle: false,
            radius: 42,
          )
        ]));
  }
}

有人知道如何创建半图吗?我还没找到任何东西。

flutter pie-chart fl-chart
1个回答
0
投票

在这种情况下,fl_chart 不是适合该工作的工具。您可以使用自定义画家来绘制您自己的图表。

这是一个可能的实现:

class GaugeChart extends StatelessWidget {
  const GaugeChart({
    super.key,
    required this.percent,
    required this.color,
    required this.backgroundColor,
    this.strokeWidth = 10,
    this.unitText,
    required this.centerTextStyle,
  });

  /// percent is between 0 and 100
  final double percent;

  /// percentile arc color
  final Color color;

  /// background arc color
  final Color backgroundColor;

  /// arc stroke width
  final double strokeWidth;

  /// text shown after the text in center
  final String? unitText;

  /// text style of the text in center
  final TextStyle centerTextStyle;

  @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 2,
      child: CustomPaint(
        painter: GaugePainter(
          percent: percent,
          color: color,
          backgroundColor: backgroundColor,
          strokeWidth: strokeWidth,
          unitText: unitText,
          centerTextStyle: centerTextStyle,
        ),
      ),
    );
  }
}

class GaugePainter extends CustomPainter {
  GaugePainter({
    required this.percent,
    required this.color,
    required this.backgroundColor,
    this.strokeWidth = 10.0,
    this.unitText,
    required this.centerTextStyle,
  });

  /// percent is between 0 and 100
  final double percent;

  /// percentile arc color
  final Color color;

  /// background arc color
  final Color backgroundColor;

  /// arc stroke width
  final double strokeWidth;

  /// text shown after the text in center
  final String? unitText;

  /// text style of the text in center
  final TextStyle centerTextStyle;

  @override
  void paint(Canvas canvas, Size size) {
    // calculate center and radius of circle
    final center = Offset(size.width / 2, size.height);
    final radius = size.width / 2 - strokeWidth / 2;

    final fullArcPainter = Paint()
      ..color = backgroundColor
      ..strokeWidth = strokeWidth
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round;

    // when painter stroke cap is StrokeCap.round, it will add half of the
    // stroke width to the start and end of arc. Therefore the angle is bigger
    // then 2 * pi (=180) degree.
    // This formula calculates the angle of the arc so the arc will be 180
    // degree including the stroke width.
    final angleWithRoundStroke = pi - strokeWidth / radius;

    // This formula calculates the offset angle of the arc so the arc will be
    // 180 degree including the stroke width.
    final offsetAngle = pi + (strokeWidth / (2 * radius));

    // Draw background arc
    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      offsetAngle,
      angleWithRoundStroke,
      false,
      fullArcPainter,
    );

    final percentPainter = Paint()
      ..color = color
      ..strokeWidth = strokeWidth
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round;

    double percentAngle;
    if (percent >= 100) {
      // catch case when percent is bigger than 100
      percentAngle = angleWithRoundStroke;
    } else {
      // calculate angle of percent arc
      percentAngle = percent * angleWithRoundStroke / 100;
    }

    // Draw percent arc
    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      offsetAngle,
      percentAngle,
      false,
      percentPainter,
    );

    // paint text
    TextSpan textSpan = TextSpan(
      text: percent.round().toString() + (unitText ?? ''),
      style: centerTextStyle,
    );
    final textPainter = TextPainter(
      text: textSpan,
      textDirection: TextDirection.ltr,
    );
    textPainter.layout(
      minWidth: 0,
      maxWidth: size.width,
    );

    final xTextPosition = (size.width - textPainter.width) / 2;
    final yTextPosition = (size.height - textPainter.height) * 3 / 4;
    final textOffset = Offset(xTextPosition, yTextPosition);
    textPainter.paint(canvas, textOffset);
  }

  @override
  bool shouldRepaint(covariant GaugePainter oldDelegate) {
    return oldDelegate.percent != percent;
  }
}

请注意,您还可以使用动画控制器来动画更改。周围应该有导游。

© www.soinside.com 2019 - 2024. All rights reserved.