import 'package:flutter/material.dart'; /// カメラ画面右端の露出スライダーを描画する CustomPainter。 /// /// - 縦トラック(白半透明) /// - 中央基準線(0 EV を示すマーカー) /// - 現在値を示すノブ(影付き白丸) class ExposureSliderPainter extends CustomPainter { final double currentValue; final double minValue; final double maxValue; const ExposureSliderPainter({ required this.currentValue, required this.minValue, required this.maxValue, }); @override void paint(Canvas canvas, Size size) { final trackPaint = Paint() ..color = Colors.white.withValues(alpha: 0.3) ..strokeWidth = 4 ..strokeCap = StrokeCap.round; final centerLinePaint = Paint() ..color = Colors.white54 ..strokeWidth = 2; final knobPaint = Paint() ..color = Colors.white ..style = PaintingStyle.fill; final knobShadowPaint = Paint() ..color = Colors.black26 ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 4); // 縦トラック(中央線) final trackX = size.width / 2; canvas.drawLine( Offset(trackX, 10), Offset(trackX, size.height - 10), trackPaint, ); // 0 EV マーカー canvas.drawLine( Offset(trackX - 6, size.height / 2), Offset(trackX + 6, size.height / 2), centerLinePaint, ); // ノブ位置を算出 final range = maxValue - minValue; if (range > 0) { // minValue(下端) → 0.0、maxValue(上端) → 1.0 に正規化してY座標に変換 final normalized = (currentValue - minValue) / range; final knobY = (size.height - 20) * (1.0 - normalized) + 10; canvas.drawCircle(Offset(trackX, knobY), 7, knobShadowPaint); canvas.drawCircle(Offset(trackX, knobY), 6, knobPaint); } } @override bool shouldRepaint(ExposureSliderPainter oldDelegate) { return oldDelegate.currentValue != currentValue || oldDelegate.minValue != minValue || oldDelegate.maxValue != maxValue; } }