투명 배경의 checkbox 만들기 - 실패

covy·2024년 6월 3일

구현하고 싶은 것

이미지처럼 배경 없는 체크 박스를 만들고 싶었다. compose material3에서 제공하는 체크박스를 사용하려고 했다.

아래처럼 해보았을 때 될 것이라고 확신했는데,, 안되더라..

@Composable
fun TransparentCheonghaCheckbox(
    modifier: Modifier = Modifier,
    checked: Boolean,
    onCheckedChanged: (Boolean) -> Unit,
) {
    Checkbox(
        modifier = modifier,
        colors = CheckboxDefaults.colors(
            checkedColor = Color.Transparent,
            uncheckedColor = Color.Transparent,
        ).copy(
            uncheckedCheckmarkColor = WithpeaceTheme.colors.SystemGray2,
            checkedCheckmarkColor = WithpeaceTheme.colors.MainPurple,
            uncheckedBoxColor = Color.Unspecified,
        ),
        checked = checked,
        onCheckedChange = onCheckedChanged,
    )
}

이유를 찾아보자..
가장 내부에 있는 코드이다. 아래 코드에 체크 색을 설정하고, Canvas를 통해 체크 모양을 그리는 방식이었다

    /**
     * Represents the color used for the checkmark inside the checkbox, depending on [state].
     *
     * @param state the [ToggleableState] of the checkbox
     */
    @Composable
    internal fun checkmarkColor(state: ToggleableState): State<Color> {
        val target = if (state == ToggleableState.Off) {
            uncheckedCheckmarkColor
        } else {
            checkedCheckmarkColor
        }

        val duration = if (state == ToggleableState.Off) BoxOutDuration else BoxInDuration
        return animateColorAsState(target, tween(durationMillis = duration))
    }

디버깅을 했을 때 색상은 문제 없이 전달되었고, Toggleablestate 또한 문제없이 전달되었다.

Canvas 코드를 보자

private fun DrawScope.drawCheck(
    checkColor: Color,
    checkFraction: Float,
    crossCenterGravitation: Float,
    strokeWidthPx: Float,
    drawingCache: CheckDrawingCache
) {
    val stroke = Stroke(width = strokeWidthPx, cap = StrokeCap.Square)
    val width = size.width
    val checkCrossX = 0.4f
    val checkCrossY = 0.7f
    val leftX = 0.2f
    val leftY = 0.5f
    val rightX = 0.8f
    val rightY = 0.3f

    val gravitatedCrossX = lerp(checkCrossX, 0.5f, crossCenterGravitation)
    val gravitatedCrossY = lerp(checkCrossY, 0.5f, crossCenterGravitation)
    // gravitate only Y for end to achieve center line
    val gravitatedLeftY = lerp(leftY, 0.5f, crossCenterGravitation)
    val gravitatedRightY = lerp(rightY, 0.5f, crossCenterGravitation)

    with(drawingCache) {
        checkPath.reset()
        checkPath.moveTo(width * leftX, width * gravitatedLeftY)
        checkPath.lineTo(width * gravitatedCrossX, width * gravitatedCrossY)
        checkPath.lineTo(width * rightX, width * gravitatedRightY)
        // TODO: replace with proper declarative non-android alternative when ready (b/158188351)
        pathMeasure.setPath(checkPath, false)
        pathToDraw.reset()
        pathMeasure.getSegment(
            0f, pathMeasure.length * checkFraction, pathToDraw, true
        )
    }
    drawPath(drawingCache.pathToDraw, checkColor, style = stroke)
}

함수 파라미터에 둘 다 0f가 들어가면 캔버스를 못 그린다.
checkFraction: Float,
crossCenterGravitation: Float,

결론

Checkbox가 unmark 상태일 때 내부 구조상 체크를 그리는 것이 불가능하다.

현재 checkmarkColor() 함수에서 왜 색상체크를 하고 있는지 알 수 없었고(의미가 없는 코드로 보인다.), 이 때문에 삽질을 오래했다..

issueTraker에 올렸다.
구현하고자 하는 체크 인터렉션은 나중에 고민하고, 그냥 벡터 이미지로 구현해야겠다..

0개의 댓글