Sensor Alignment: 방향 화살표 → arrow_transparent.png 교체 (rotate + tint)
자산:
- drawable/arrow_transparent.png 신규 (132×112 RGBA, 우향 thin arrow)
코드:
- drawLine 3개로 구성하던 화살표 → drawImage(arrowBitmap) 한 번으로 교체
- 4방향은 rotate(degrees, pivot) 로 처리:
right=0° / down=90° / left=180° / up=-90°
- ColorFilter.tint(#E64A19 × arrowAlpha) — 일러스트 톤 매칭 + blink 유지
- arrowDrawW=90f, 높이는 icon aspect(132:112)로 비례
- center 위치는 bladder oval edge + sensorHalfH + gap + arrowSize/2
기존 blink 로직(scanCount % 2 → animateFloatAsState 180ms)은 그대로 동작 —
tint color 의 alpha 에 arrowAlpha 를 곱하므로 PNG 도 매 refresh 깜빡임.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+56
-31
@@ -368,6 +368,13 @@ fun PlacementGuideView(appState: AppState) {
|
||||
com.example.medilightv2android.R.drawable.sensor_device,
|
||||
).asImageBitmap()
|
||||
}
|
||||
// 방향 화살표 PNG (132x112, 우향). 회전 + tint 로 4방향 + 색감 통일.
|
||||
val arrowBitmap = remember {
|
||||
android.graphics.BitmapFactory.decodeResource(
|
||||
context.resources,
|
||||
com.example.medilightv2android.R.drawable.arrow_transparent,
|
||||
).asImageBitmap()
|
||||
}
|
||||
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||
val w = size.width
|
||||
val h = size.height
|
||||
@@ -416,41 +423,59 @@ fun PlacementGuideView(appState: AppState) {
|
||||
alpha = 0.95f,
|
||||
)
|
||||
|
||||
// ── 방향 화살표 (센서/타원 바깥) — 매 refresh 마다 alpha 깜빡임 ──
|
||||
// 색감 #FF5722 → #E64A19 (deep orange 700, 일러스트와 톤 맞춤)
|
||||
// StrokeCap.Round로 끝부분 둥글게 + 굵기 9→10 (가독성)
|
||||
// ── 방향 화살표 (PNG icon, rotate + tint) — 매 refresh 마다 alpha 깜빡임 ──
|
||||
// arrow_transparent.png 는 우향(→) 132×112. 회전으로 4방향 처리.
|
||||
// tint = deep orange 700 (#E64A19) — 일러스트 톤 맞춤 + alpha 로 blink.
|
||||
if (!greenZone) {
|
||||
val arrowColor = Color(0xFFE64A19).copy(alpha = arrowAlpha)
|
||||
val arrowLen = 70f
|
||||
val arrowHead = 28f
|
||||
val sw = 10f
|
||||
val cap = androidx.compose.ui.graphics.StrokeCap.Round
|
||||
val arrowDrawW = 90f
|
||||
val arrowDrawH = arrowDrawW * (arrowBitmap.height.toFloat() / arrowBitmap.width.toFloat())
|
||||
val sensorHalfH = h * 0.08f
|
||||
val gap = 20f
|
||||
|
||||
when {
|
||||
directionIcon.contains("up") -> {
|
||||
val ay = bladderCy - bladderRy - sensorHalfH - 20f
|
||||
drawLine(arrowColor, Offset(cx, ay + arrowLen), Offset(cx, ay), strokeWidth = sw, cap = cap)
|
||||
drawLine(arrowColor, Offset(cx - arrowHead, ay + arrowHead), Offset(cx, ay), strokeWidth = sw, cap = cap)
|
||||
drawLine(arrowColor, Offset(cx + arrowHead, ay + arrowHead), Offset(cx, ay), strokeWidth = sw, cap = cap)
|
||||
// 화살표 center 위치 + 회전 각도 (icon 이 우향이므로 right=0°)
|
||||
data class ArrowPlacement(val cxa: Float, val cya: Float, val rot: Float)
|
||||
val placement: ArrowPlacement? = when {
|
||||
directionIcon.contains("up") -> ArrowPlacement(
|
||||
cx,
|
||||
bladderCy - bladderRy - sensorHalfH - gap - arrowDrawH / 2f,
|
||||
-90f,
|
||||
)
|
||||
directionIcon.contains("down") -> ArrowPlacement(
|
||||
cx,
|
||||
bladderCy + bladderRy + sensorHalfH + gap + arrowDrawH / 2f,
|
||||
90f,
|
||||
)
|
||||
directionIcon.contains("left") -> ArrowPlacement(
|
||||
cx - bladderRx - gap - arrowDrawW / 2f,
|
||||
bladderCy,
|
||||
180f,
|
||||
)
|
||||
directionIcon.contains("right") -> ArrowPlacement(
|
||||
cx + bladderRx + gap + arrowDrawW / 2f,
|
||||
bladderCy,
|
||||
0f,
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
directionIcon.contains("down") -> {
|
||||
val ay = bladderCy + bladderRy + sensorHalfH + 20f
|
||||
drawLine(arrowColor, Offset(cx, ay - arrowLen), Offset(cx, ay), strokeWidth = sw, cap = cap)
|
||||
drawLine(arrowColor, Offset(cx - arrowHead, ay - arrowHead), Offset(cx, ay), strokeWidth = sw, cap = cap)
|
||||
drawLine(arrowColor, Offset(cx + arrowHead, ay - arrowHead), Offset(cx, ay), strokeWidth = sw, cap = cap)
|
||||
}
|
||||
directionIcon.contains("left") -> {
|
||||
val ax = cx - bladderRx - 30f
|
||||
drawLine(arrowColor, Offset(ax + arrowLen, bladderCy), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
||||
drawLine(arrowColor, Offset(ax + arrowHead, bladderCy - arrowHead), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
||||
drawLine(arrowColor, Offset(ax + arrowHead, bladderCy + arrowHead), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
||||
}
|
||||
directionIcon.contains("right") -> {
|
||||
val ax = cx + bladderRx + 30f
|
||||
drawLine(arrowColor, Offset(ax - arrowLen, bladderCy), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
||||
drawLine(arrowColor, Offset(ax - arrowHead, bladderCy - arrowHead), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
||||
drawLine(arrowColor, Offset(ax - arrowHead, bladderCy + arrowHead), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
||||
if (placement != null) {
|
||||
val tint = androidx.compose.ui.graphics.ColorFilter.tint(
|
||||
Color(0xFFE64A19).copy(alpha = arrowAlpha)
|
||||
)
|
||||
rotate(degrees = placement.rot, pivot = Offset(placement.cxa, placement.cya)) {
|
||||
drawImage(
|
||||
image = arrowBitmap,
|
||||
srcOffset = androidx.compose.ui.unit.IntOffset.Zero,
|
||||
srcSize = androidx.compose.ui.unit.IntSize(arrowBitmap.width, arrowBitmap.height),
|
||||
dstOffset = androidx.compose.ui.unit.IntOffset(
|
||||
(placement.cxa - arrowDrawW / 2f).toInt(),
|
||||
(placement.cya - arrowDrawH / 2f).toInt(),
|
||||
),
|
||||
dstSize = androidx.compose.ui.unit.IntSize(
|
||||
arrowDrawW.toInt(),
|
||||
arrowDrawH.toInt(),
|
||||
),
|
||||
colorFilter = tint,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
Reference in New Issue
Block a user