仪表盘 样式优化
This commit is contained in:
@@ -142,13 +142,13 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
|
||||
);
|
||||
}
|
||||
|
||||
// ====================== 大半个圆仪表盘(电压/芯片温度) ======================
|
||||
Widget _largeArcGauge({
|
||||
// ====================== 圆形仪表盘(匹配目标样式) ======================
|
||||
Widget _circularGauge({
|
||||
required double value,
|
||||
required double maxValue,
|
||||
required String unit,
|
||||
required String label,
|
||||
List<double> majorTicks = const [0, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250],
|
||||
List<double> majorTicks = const [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
|
||||
}) {
|
||||
return SizedBox(
|
||||
height: 220,
|
||||
@@ -156,14 +156,14 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
CustomPaint(
|
||||
painter: LargeArcGaugePainter(value: value / maxValue, maxValue: maxValue, majorTicks: majorTicks),
|
||||
size: const Size(300, 180),
|
||||
painter: CircularGaugePainter(value: value, maxValue: maxValue, majorTicks: majorTicks),
|
||||
size: const Size(280, 280),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
bottom: 20,
|
||||
child: Text(
|
||||
"${value.toStringAsFixed(2)} $unit",
|
||||
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.grey),
|
||||
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500, color: Colors.grey),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -368,13 +368,7 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_voltageGaugeMode
|
||||
? _largeArcGauge(
|
||||
value: status.voltage,
|
||||
maxValue: 250,
|
||||
unit: "V",
|
||||
label: "电压",
|
||||
majorTicks: const [0, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250],
|
||||
)
|
||||
? _circularGauge(value: status.voltage, maxValue: 250, unit: "V", label: "电压", majorTicks: const [0, 50, 100, 150, 200, 250])
|
||||
: SizedBox(
|
||||
height: 200,
|
||||
child: _styledLineChart(
|
||||
@@ -424,7 +418,7 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_chipTempGaugeMode
|
||||
? _largeArcGauge(
|
||||
? _circularGauge(
|
||||
value: status.chipTemp,
|
||||
maxValue: 100,
|
||||
unit: "°C",
|
||||
@@ -480,7 +474,7 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_knifeSpeedGaugeMode
|
||||
? _largeArcGauge(
|
||||
? _circularGauge(
|
||||
value: double.tryParse(status.knifeCuttingSpeed) ?? 0,
|
||||
maxValue: 3000,
|
||||
unit: "rpm",
|
||||
@@ -854,88 +848,105 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== 大半个圆仪表盘绘制器 ======================
|
||||
class LargeArcGaugePainter extends CustomPainter {
|
||||
// ====================== 圆形仪表盘绘制器(匹配目标样式) ======================
|
||||
class CircularGaugePainter extends CustomPainter {
|
||||
final double value;
|
||||
final double maxValue;
|
||||
final List<double> majorTicks;
|
||||
|
||||
LargeArcGaugePainter({required this.value, required this.maxValue, required this.majorTicks});
|
||||
CircularGaugePainter({required this.value, required this.maxValue, required this.majorTicks});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final center = Offset(size.width / 2, size.height);
|
||||
// 画布中心和半径(留出边距)
|
||||
final center = Offset(size.width / 2, size.height / 2);
|
||||
final radius = size.width / 2 - 20;
|
||||
|
||||
// 背景弧(大半个圆,从 -135° 到 135°)
|
||||
final bgPaint = Paint()
|
||||
// 1. 绘制背景圆弧(浅蓝底色,270°范围:从135°到405°,对应左下到右下的半圆)
|
||||
final bgArcPaint = Paint()
|
||||
..color = const Color(0xFFE3F2FD)
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 20
|
||||
..strokeWidth = 8
|
||||
..strokeCap = StrokeCap.round;
|
||||
final bgRect = Rect.fromCircle(center: center, radius: radius);
|
||||
canvas.drawArc(bgRect, 135 * math.pi / 180, 270 * math.pi / 180, false, bgArcPaint);
|
||||
|
||||
canvas.drawArc(Rect.fromCircle(center: center, radius: radius), -135 * math.pi / 180, 270 * math.pi / 180, false, bgPaint);
|
||||
|
||||
// 进度弧
|
||||
// 2. 绘制进度圆弧(浅蓝色,根据数值比例绘制)
|
||||
final progressRatio = math.min(value / maxValue, 1.0); // 限制最大为1
|
||||
final progressPaint = Paint()
|
||||
..color = const Color(0xFFBBDEFB)
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 20
|
||||
..strokeWidth = 8
|
||||
..strokeCap = StrokeCap.round;
|
||||
canvas.drawArc(bgRect, 135 * math.pi / 180, 270 * math.pi / 180 * progressRatio, false, progressPaint);
|
||||
|
||||
canvas.drawArc(Rect.fromCircle(center: center, radius: radius), -135 * math.pi / 180, 270 * math.pi / 180 * value, false, progressPaint);
|
||||
|
||||
// 刻度
|
||||
final tickPaint = Paint()
|
||||
..color = Colors.black54
|
||||
// 3. 绘制刻度(主刻度+副刻度)
|
||||
final tickPaint = Paint()..color = Colors.grey.shade400;
|
||||
final majorTickPaint = Paint()
|
||||
..color = Colors.grey.shade600
|
||||
..strokeWidth = 2;
|
||||
|
||||
for (int i = 0; i <= 45; i++) {
|
||||
final angle = -135 * math.pi / 180 + (270 * math.pi / 180) * (i / 45);
|
||||
final x1 = center.dx + (radius - 15) * math.cos(angle);
|
||||
final y1 = center.dy + (radius - 15) * math.sin(angle);
|
||||
final x2 = center.dx + radius * math.cos(angle);
|
||||
final y2 = center.dy + radius * math.sin(angle);
|
||||
canvas.drawLine(Offset(x1, y1), Offset(x2, y2), tickPaint);
|
||||
// 总刻度数(每1°一个副刻度,每10°一个主刻度)
|
||||
const totalTicks = 270;
|
||||
for (int i = 0; i < totalTicks; i++) {
|
||||
// 计算刻度角度(从135°开始,到405°结束)
|
||||
final angle = 135 * math.pi / 180 + (i * math.pi * 270 / 180) / totalTicks;
|
||||
// 刻度起始和结束位置
|
||||
final tickStart = center + Offset(math.cos(angle), math.sin(angle)) * (radius - 4);
|
||||
final tickEnd = center + Offset(math.cos(angle), math.sin(angle)) * radius;
|
||||
|
||||
// 主刻度
|
||||
if (majorTicks.contains(i * (maxValue / 45))) {
|
||||
final x3 = center.dx + (radius - 25) * math.cos(angle);
|
||||
final y3 = center.dy + (radius - 25) * math.sin(angle);
|
||||
canvas.drawLine(Offset(x1, y1), Offset(x3, y3), tickPaint..strokeWidth = 4);
|
||||
// 副刻度(短刻度)
|
||||
tickPaint.strokeWidth = 1;
|
||||
canvas.drawLine(tickStart, tickEnd, tickPaint);
|
||||
|
||||
// 刻度值
|
||||
final textValue = (i * (maxValue / 45)).toStringAsFixed(0);
|
||||
// 主刻度(长刻度,匹配majorTicks的数值)
|
||||
final tickValue = (i / totalTicks) * maxValue;
|
||||
if (majorTicks.any((tick) => (tickValue - tick).abs() < 0.1)) {
|
||||
final majorTickStart = center + Offset(math.cos(angle), math.sin(angle)) * (radius - 8);
|
||||
canvas.drawLine(majorTickStart, tickEnd, majorTickPaint);
|
||||
|
||||
// 绘制主刻度数值
|
||||
final textValue = tickValue.toStringAsFixed(0);
|
||||
final textPainter = TextPainter(
|
||||
text: TextSpan(
|
||||
text: textValue,
|
||||
style: const TextStyle(fontSize: 16, color: Colors.black54),
|
||||
style: const TextStyle(fontSize: 14, color: Colors.grey, fontWeight: FontWeight.w500),
|
||||
),
|
||||
textDirection: TextDirection.ltr,
|
||||
)..layout();
|
||||
final textX = center.dx + (radius - 40) * math.cos(angle) - textPainter.width / 2;
|
||||
final textY = center.dy + (radius - 40) * math.sin(angle) - textPainter.height / 2;
|
||||
// 数值位置(在主刻度外侧)
|
||||
final textOffset = center + Offset(math.cos(angle), math.sin(angle)) * (radius - 20);
|
||||
final textX = textOffset.dx - textPainter.width / 2;
|
||||
final textY = textOffset.dy - textPainter.height / 2;
|
||||
textPainter.paint(canvas, Offset(textX, textY));
|
||||
}
|
||||
}
|
||||
|
||||
// 指针(修正方向)
|
||||
final needleAngle = -135 * math.pi / 180 + 270 * math.pi / 180 * value;
|
||||
// 4. 绘制指针
|
||||
final needleAngle = 135 * math.pi / 180 + 270 * math.pi / 180 * progressRatio;
|
||||
final needlePaint = Paint()
|
||||
..color = const Color(0xFF90A4AE)
|
||||
..color = Colors.grey.shade400
|
||||
..style = PaintingStyle.fill;
|
||||
|
||||
// 指针形状(三角形)
|
||||
final needlePath = Path()
|
||||
..moveTo(center.dx, center.dy)
|
||||
..lineTo(center.dx + radius * 0.8 * math.cos(needleAngle - 0.03), center.dy + radius * 0.8 * math.sin(needleAngle - 0.03))
|
||||
..lineTo(center.dx + radius * 0.8 * math.cos(needleAngle + 0.03), center.dy + radius * 0.8 * math.sin(needleAngle + 0.03))
|
||||
..lineTo(center.dx + (radius - 20) * math.cos(needleAngle - 0.02), center.dy + (radius - 20) * math.sin(needleAngle - 0.02))
|
||||
..lineTo(center.dx + (radius - 20) * math.cos(needleAngle + 0.02), center.dy + (radius - 20) * math.sin(needleAngle + 0.02))
|
||||
..close();
|
||||
|
||||
canvas.drawPath(needlePath, needlePaint);
|
||||
|
||||
// 5. 绘制指针中心圆点
|
||||
final centerDotPaint = Paint()
|
||||
..color = Colors.grey.shade400
|
||||
..style = PaintingStyle.fill;
|
||||
canvas.drawCircle(center, 6, centerDotPaint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
||||
bool shouldRepaint(covariant CircularGaugePainter oldDelegate) {
|
||||
return oldDelegate.value != value || oldDelegate.maxValue != maxValue;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== 罗盘式航向角仪表盘绘制器 ======================
|
||||
|
||||
Reference in New Issue
Block a user