如何在圆Flutter中显示自定义Angular 多弧起始

k4emjkb1  于 2023-05-01  发布在  Flutter
关注(0)|答案(1)|浏览(113)

我正在寻找代表的时间范围在12小时时钟我试图代表几个彩色弧在一个圆,每个弧已指定的开始Angular

我已经使用同步融合软件包,它允许设置开始Angular ,但只为主要的圆圈,而不是forevery弧
我尝试了许多软件包作为fl图表,饼图,同步融合,但我没有得到我所寻找的

yhuiod9q

yhuiod9q1#

我试着实现它,并想出了以下解决方案

import 'dart:math';
import 'dart:ui';

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

void main() {
  runApp(
    const MyApp(),
  );
}

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

  @override
  Widget build(BuildContext context) {
    const title = 'Pie Chart';
    return MaterialApp(
      title: title,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(title),
        ),
        body: const Center(
          child: SizedBox.square(
            dimension: 200,
            child: PieChart(
              // data could be list of num
              data: [64, 128, 73, 15, 72],
//              color: Colors.green,
              dividerColor: Colors.white,
              minOpacity: 0.2,
              startAngle: 65,
//              dividerWidth: 5,
            ),
          ),
        ),
      ),
    );
  }
}

class PieChart<T extends num> extends StatelessWidget {
  final double? startAngle;
  final int? dividerWidth;
  final Color? dividerColor;
  final Color? color;
  final double? minOpacity;
  final List<T> data;

  const PieChart({
    super.key,
    required this.data,
    this.startAngle,
    this.dividerWidth,
    this.dividerColor,
    this.color,
    this.minOpacity,
  });
  @override
  Widget build(BuildContext context) {
    final inheritedTheme = Theme.of(context).extension<PieChartTheme>() ??
        PieChartTheme(
          color: Theme.of(context).primaryColor,
        );

    final pieChartTheme = PieChartTheme(
      color: color ?? inheritedTheme.color,
      dividerColor: dividerColor ?? inheritedTheme.dividerColor,
      dividerWidth: dividerWidth ?? inheritedTheme.dividerWidth,
      startAngle: startAngle ?? inheritedTheme.startAngle,
      minOpacity: minOpacity ?? inheritedTheme.minOpacity,
    );

    return CustomPaint(
      painter: _PieChartPainter(
        data: data,
        pieChartTheme: pieChartTheme,
      ),
    );
  }
}

class _PieChartPainter<T extends num> extends CustomPainter {
  final PieChartTheme pieChartTheme;
  final List<T> data;

  const _PieChartPainter({required this.data, required this.pieChartTheme});

  @override
  void paint(Canvas canvas, Size size) {
    final total = data.fold(0.0, (p, e) => p + e);

    final rect = Rect.fromLTRB(0, 0, size.width, size.height);
    final radius = rect.center.dx;

    double startAngle = Angle.degrees(pieChartTheme.startAngle).radians;
    double sweepAngle = 0;

    final paint = Paint()
      ..style = PaintingStyle.fill
      ..strokeWidth = pieChartTheme.dividerWidth.toDouble();

    final dividerColor = pieChartTheme.dividerColor;

    for (var i = 0; i < data.length; i++) {
      startAngle += sweepAngle;
      sweepAngle = data[i] / total * 2 * pi;

      double opacity = 1.0 - i / data.length * (1 - pieChartTheme.minOpacity);
      final color = pieChartTheme.color!.withOpacity(opacity);
      paint
        ..color = color
        ..style = PaintingStyle.fill;

      final path = Path()
        ..moveTo(rect.center.dx, rect.center.dy)
        ..lineTo(radius * cos(startAngle + sweepAngle),
            radius * sin(startAngle + sweepAngle))
        ..addArc(Rect.fromLTRB(0, 0, size.width, size.height), startAngle,
            sweepAngle)
        ..lineTo(rect.center.dx, rect.center.dy)
        ..close();

      canvas.drawPath(path, paint);

      if (dividerColor != null) {
        paint.style = PaintingStyle.stroke;
        paint.color = dividerColor;
        canvas.save();
        canvas.translate(rect.center.dx, rect.center.dy);
        Path path = Path()
          ..moveTo(0, 0)
          ..lineTo(radius * cos(startAngle), radius * sin(startAngle))
          ..moveTo(radius * cos(startAngle + sweepAngle),
              radius * sin(startAngle + sweepAngle))
          ..lineTo(0, 0)
          ..close();

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

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

class PieChartTheme extends ThemeExtension<PieChartTheme> {
  final double startAngle;
  final int dividerWidth;
  final Color? dividerColor;
  final Color? color;
  final double minOpacity;

  PieChartTheme(
      {this.startAngle = 0,
      this.dividerWidth = 2,
      this.dividerColor,
      this.color,
      this.minOpacity = 0.5});

  @override
  ThemeExtension<PieChartTheme> lerp(covariant PieChartTheme? other, double t) {
    if (other == null) {
      return this;
    }
    return PieChartTheme(
      startAngle: lerpDouble(startAngle, other.startAngle, t)!,
      color: Color.lerp(color, other.color, t),
      dividerColor: Color.lerp(color, other.color, t),
      dividerWidth:
          (dividerWidth + (other.dividerWidth - dividerWidth) * t).round(),
      minOpacity: lerpDouble(minOpacity, other.minOpacity, t)!,
    );
  }

  @override
  ThemeExtension<PieChartTheme> copyWith({
    double? startAngle,
    int? dividerWidth,
    Color? dividerColor,
    Color? color,
    double? minOpacity,
  }) {
    return PieChartTheme(
      startAngle: startAngle ?? this.startAngle,
      dividerWidth: dividerWidth ?? this.dividerWidth,
      dividerColor: dividerColor ?? this.dividerColor,
      color: color ?? this.color,
      minOpacity: minOpacity ?? this.minOpacity,
    );
  }
}

angles包是依赖性。
样本输出

相关问题