如何绘制圆角边框饼图

F.S*_*SO7 6 charts dart flutter flutter-dependencies flutter-layout

我正在尝试构建一个饼图,如下所示:

图像

我已经尝试过Flutter_ChartsFL_Chart,但似乎都不支持饼图中的圆角和间隔项目。

有谁知道实现这种饼图设计的最佳方法是什么?

谢谢你!

小智 1

使用CustomPaint小部件可以轻松实现与图表非常相似的版本。

这是结果图表
结果图表

要实现这一点,您只需要一个非常基本的CustomPainter,它可以在画布上绘制弧线。舍入效果是通过用于绘制描边的PaintStrokeCap属性来实现的。遗憾的是StrokeCap仅支持圆形和方形笔画结尾。 通过这种方式无法实现像您的屏幕截图中那样的圆角矩形效果。 颜色是通过对每个笔画使用单独的Paint来实现的。

// this is used to pass data about chart values to the widget
class PieChartData {
  const PieChartData(this.color, this.percent);

  final Color color;
  final double percent;
}

// our pie chart widget
class PieChart extends StatelessWidget {
  PieChart({
    required this.data,
    required this.radius,
    this.strokeWidth = 8,
    this.child,
    Key? key,
  })  : // make sure sum of data is never ovr 100 percent
        assert(data.fold<double>(0, (sum, data) => sum + data.percent) <= 100),
        super(key: key);

  final List<PieChartData> data;
  // radius of chart
  final double radius;
  // width of stroke
  final double strokeWidth;
  // optional child; can be used for text for example
  final Widget? child;

  @override
  Widget build(context) {
    return CustomPaint(
      painter: _Painter(strokeWidth, data),
      size: Size.square(radius),
      child: SizedBox.square(
        // calc diameter
        dimension: radius * 2,
        child: Center(
          child: child,
        ),
      ),
    );
  }
}

// responsible for painting our chart
class _PainterData {
  const _PainterData(this.paint, this.radians);

  final Paint paint;
  final double radians;
}

class _Painter extends CustomPainter {
  _Painter(double strokeWidth, List<PieChartData> data) {
    // convert chart data to painter data
    dataList = data
        .map((e) => _PainterData(
              Paint()
                ..color = e.color
                ..style = PaintingStyle.stroke
                ..strokeWidth = strokeWidth
                ..strokeCap = StrokeCap.round,
              // remove padding from stroke
              (e.percent - _padding) * _percentInRadians,
            ))
        .toList();
  }

  static const _percentInRadians = 0.062831853071796;
  // this is the gap between strokes in percent
  static const _padding = 4;
  static const _paddingInRadians = _percentInRadians * _padding;
  // 0 radians is to the right, but since we want to start from the top
  // we'll use -90 degrees in radians
  static const _startAngle = -1.570796 + _paddingInRadians / 2;

  late final List<_PainterData> dataList;

  @override
  void paint(Canvas canvas, Size size) {
    final rect = Offset.zero & size;
    // keep track of start angle for next stroke
    double startAngle = _startAngle;

    for (final data in dataList) {
      final path = Path()..addArc(rect, startAngle, data.radians);

      startAngle += data.radians + _paddingInRadians;

      canvas.drawPath(path, data.paint);
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return oldDelegate != this;
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以查看dartpad来尝试一个工作示例。

我确信您在该图片中提供的相同图表可以使用 CustomPainter 实现,但这会复杂得多。