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,
|
com.example.medilightv2android.R.drawable.sensor_device,
|
||||||
).asImageBitmap()
|
).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()) {
|
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||||
val w = size.width
|
val w = size.width
|
||||||
val h = size.height
|
val h = size.height
|
||||||
@@ -416,41 +423,59 @@ fun PlacementGuideView(appState: AppState) {
|
|||||||
alpha = 0.95f,
|
alpha = 0.95f,
|
||||||
)
|
)
|
||||||
|
|
||||||
// ── 방향 화살표 (센서/타원 바깥) — 매 refresh 마다 alpha 깜빡임 ──
|
// ── 방향 화살표 (PNG icon, rotate + tint) — 매 refresh 마다 alpha 깜빡임 ──
|
||||||
// 색감 #FF5722 → #E64A19 (deep orange 700, 일러스트와 톤 맞춤)
|
// arrow_transparent.png 는 우향(→) 132×112. 회전으로 4방향 처리.
|
||||||
// StrokeCap.Round로 끝부분 둥글게 + 굵기 9→10 (가독성)
|
// tint = deep orange 700 (#E64A19) — 일러스트 톤 맞춤 + alpha 로 blink.
|
||||||
if (!greenZone) {
|
if (!greenZone) {
|
||||||
val arrowColor = Color(0xFFE64A19).copy(alpha = arrowAlpha)
|
val arrowDrawW = 90f
|
||||||
val arrowLen = 70f
|
val arrowDrawH = arrowDrawW * (arrowBitmap.height.toFloat() / arrowBitmap.width.toFloat())
|
||||||
val arrowHead = 28f
|
|
||||||
val sw = 10f
|
|
||||||
val cap = androidx.compose.ui.graphics.StrokeCap.Round
|
|
||||||
val sensorHalfH = h * 0.08f
|
val sensorHalfH = h * 0.08f
|
||||||
|
val gap = 20f
|
||||||
|
|
||||||
when {
|
// 화살표 center 위치 + 회전 각도 (icon 이 우향이므로 right=0°)
|
||||||
directionIcon.contains("up") -> {
|
data class ArrowPlacement(val cxa: Float, val cya: Float, val rot: Float)
|
||||||
val ay = bladderCy - bladderRy - sensorHalfH - 20f
|
val placement: ArrowPlacement? = when {
|
||||||
drawLine(arrowColor, Offset(cx, ay + arrowLen), Offset(cx, ay), strokeWidth = sw, cap = cap)
|
directionIcon.contains("up") -> ArrowPlacement(
|
||||||
drawLine(arrowColor, Offset(cx - arrowHead, ay + arrowHead), Offset(cx, ay), strokeWidth = sw, cap = cap)
|
cx,
|
||||||
drawLine(arrowColor, Offset(cx + arrowHead, ay + arrowHead), Offset(cx, ay), strokeWidth = sw, cap = cap)
|
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") -> {
|
if (placement != null) {
|
||||||
val ay = bladderCy + bladderRy + sensorHalfH + 20f
|
val tint = androidx.compose.ui.graphics.ColorFilter.tint(
|
||||||
drawLine(arrowColor, Offset(cx, ay - arrowLen), Offset(cx, ay), strokeWidth = sw, cap = cap)
|
Color(0xFFE64A19).copy(alpha = arrowAlpha)
|
||||||
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)
|
rotate(degrees = placement.rot, pivot = Offset(placement.cxa, placement.cya)) {
|
||||||
}
|
drawImage(
|
||||||
directionIcon.contains("left") -> {
|
image = arrowBitmap,
|
||||||
val ax = cx - bladderRx - 30f
|
srcOffset = androidx.compose.ui.unit.IntOffset.Zero,
|
||||||
drawLine(arrowColor, Offset(ax + arrowLen, bladderCy), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
srcSize = androidx.compose.ui.unit.IntSize(arrowBitmap.width, arrowBitmap.height),
|
||||||
drawLine(arrowColor, Offset(ax + arrowHead, bladderCy - arrowHead), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
dstOffset = androidx.compose.ui.unit.IntOffset(
|
||||||
drawLine(arrowColor, Offset(ax + arrowHead, bladderCy + arrowHead), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
(placement.cxa - arrowDrawW / 2f).toInt(),
|
||||||
}
|
(placement.cya - arrowDrawH / 2f).toInt(),
|
||||||
directionIcon.contains("right") -> {
|
),
|
||||||
val ax = cx + bladderRx + 30f
|
dstSize = androidx.compose.ui.unit.IntSize(
|
||||||
drawLine(arrowColor, Offset(ax - arrowLen, bladderCy), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
arrowDrawW.toInt(),
|
||||||
drawLine(arrowColor, Offset(ax - arrowHead, bladderCy - arrowHead), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
arrowDrawH.toInt(),
|
||||||
drawLine(arrowColor, Offset(ax - arrowHead, bladderCy + arrowHead), Offset(ax, bladderCy), strokeWidth = sw, cap = cap)
|
),
|
||||||
|
colorFilter = tint,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
Reference in New Issue
Block a user