功能不完善,只是单纯的实现功能,作为记录,仅供参考:
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:lifeline/utils/hex_color_utils.dart';
class RingComponent extends StatelessWidget {
final double radius;
final Function onTap;
RingComponent({ required this.radius, required this.onTap });
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
SizedBox(
width: radius * 2,
height: radius * 2,
child: CustomPaint(
painter: RingPainter(width: radius*0.6, radius: radius),
),
),
SizedBox(
width: radius * 0.9,
height: radius * 0.9,
child: FloatingActionButton(
onPressed: () {onTap();},
mini: false,
materialTapTargetSize: MaterialTapTargetSize.padded,
child: const Icon(
Icons.sticky_note_2,
color: Colors.white,
),
),
),
],
);
}
}
class RingPainter extends CustomPainter {
final double width;
final double radius;
RingPainter({required this.width, required this.radius});
@override
void paint(Canvas canvas, Size size) {
final rect = Rect.fromCircle(
center: size.center(Offset.zero), radius: size.width / 2);
canvas.translate(20.w, -15.w);
canvas.save();
canvas.rotate(math.pi / 9);
const startAngle = -math.pi / 2;
const sweepAngle = math.pi * 2 / 3;
final innerRadius = size.width / 2 - width / 2;
final outerRadius = size.width / 2 + width / 2;
final innerPoint1 =
calculatePointOnRing(size, startAngle + sweepAngle, innerRadius);
final innerPoint2 =
calculatePointOnRing(size, startAngle + 2 * sweepAngle, innerRadius);
final innerPoint3 =
calculatePointOnRing(size, startAngle + 3 * sweepAngle, innerRadius);
final outerPoint1 =
calculatePointOnRing(size, startAngle + sweepAngle, outerRadius);
final outerPoint2 =
calculatePointOnRing(size, startAngle + 2 * sweepAngle, outerRadius);
final outerPoint3 =
calculatePointOnRing(size, startAngle + 3 * sweepAngle, outerRadius);
final colors = [HexColor("516fd5"), HexColor("f8df2d"), HexColor("f2eeeb")];
final texts = ['Intervention', 'Plan', 'Reflection'];
final paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = width;
for (int i = 0; i < colors.length; i++) {
paint.color = colors[i];
final start = startAngle + i * sweepAngle;
const sweep = sweepAngle;
canvas.drawArc(rect, start, sweep, false, paint);
}
final arrowBluePaint = Paint()
..style = PaintingStyle.fill
..isAntiAlias = true
..color = HexColor("516fd5");
final arrowBluePath = Path();
arrowBluePath.moveTo(innerPoint1.dx + 0.6, innerPoint1.dy);
arrowBluePath.lineTo(outerPoint1.dx, outerPoint1.dy - 0.4);
arrowBluePath.lineTo(
innerPoint1.dx, innerPoint1.dy + math.sqrt(1 / 2) * width + 5);
arrowBluePath.close();
canvas.drawPath(arrowBluePath, arrowBluePaint);
final arrowYellowPaint = Paint()
..style = PaintingStyle.fill
..isAntiAlias = true
..color = HexColor("f8df2d");
final arrowYellowPath = Path();
arrowYellowPath.moveTo(innerPoint2.dx + 0.2, innerPoint2.dy);
arrowYellowPath.lineTo(outerPoint2.dx, outerPoint2.dy + 0.4);
arrowYellowPath.lineTo(
outerPoint2.dx, outerPoint2.dy - math.sqrt(1 / 2) * width - 5);
arrowYellowPath.close();
canvas.drawPath(arrowYellowPath, arrowYellowPaint);
final arrowGrayPaint = Paint()
..style = PaintingStyle.fill
..isAntiAlias = true
..color = HexColor("f2eeeb");
final arrowGrayPath = Path();
arrowGrayPath.moveTo(innerPoint3.dx, innerPoint3.dy);
arrowGrayPath.lineTo(outerPoint3.dx, outerPoint3.dy);
arrowGrayPath.lineTo(
0.6 * width + outerPoint3.dx, outerPoint3.dy + 1 / 2 * width + 5);
arrowGrayPath.close();
canvas.drawPath(arrowGrayPath, arrowGrayPaint);
// draw text
canvas.restore();
final textPainter = TextPainter(
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
for (int i = 0; i < texts.length; i++) {
final textSpan = TextSpan(
text: texts[i],
style: TextStyle(fontSize: 10.sp, color: Colors.grey),
);
textPainter.text = textSpan;
textPainter.layout();
double x;
double y;
if (i == 2) {
//reflection
x = (outerPoint1.dx + outerPoint2.dx) / 2 -
textPainter.width / 2 -
radius * 0.8;
y = (outerPoint1.dy + outerPoint2.dy) / 2 +
radius * 0.5 -
textPainter.height / 2;
} else if (i == 0) {
//intervention
x = (outerPoint2.dx + outerPoint3.dx) / 2 -
textPainter.width / 2 +
radius * 0.1;
y = (outerPoint2.dy + outerPoint3.dy) / 2 +
radius * 0.5 -
textPainter.height / 2 -
radius * 0.8;
} else {
//plan
x = (outerPoint3.dx + outerPoint1.dx) / 2 - textPainter.width / 2;
y = (outerPoint3.dy + outerPoint1.dy) / 2 +
radius * 0.7 -
textPainter.height / 2;
}
final textOffset = Offset(x, y);
textPainter.paint(canvas, textOffset);
}
}
Offset calculatePointOnRing(Size size, double angle, double radius) {
final centerX = size.width / 2;
final centerY = size.height / 2;
final x = centerX + math.cos(angle) * radius;
final y = centerY + math.sin(angle) * radius;
return Offset(x, y);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}