본문 바로가기
Android

Color 알파(alpha)값 계산기 개발기

by 역삼동개발자D 2024. 9. 13.
반응형

추석 휴일을 맞이하면서 약간의 짬이 나서 그동안 생각만했던 투명도 계산기를 개발하였다. 그러면서 겸사겸사 오랜만에 포스팅도 해본다ㅎ

 

디자인 파일을 보면서 개발하다보면 alpha가 %로 설정되어있는데 자동으로 그 값이 Hex로 변환되지 않아 인터넷의 투명도 정리 파일을 찾아야하는 경우가 종종 있다. 몇몇의 대표적인 값들은 외우게 되었지만 그래도 까먹거나 잘 사용하지 않는 alpha값이 나오면 여전히 인터넷행이었다. 그래서 이참에 연습삼아 데스트톱용 앱을 만들어보자는 생각을 하게되었다. 그럼 시작해보자.

 

Kotlin Multiplatform을 활용한 Alpha 계산기 desktop 앱 개발

왜 kmm을 선택했냐 묻는다면... 안드로이드 앱 개발에 친숙해서였다. kotlin 언어, compose 모두 익숙했기 때문에 여러 선택지들 중에서는 베스트였다.(다만 build.gradle은 조금 많이 헤맸다......)

 

결론부터 말하자면 앱 이미지를 패키지화했고 데스크톱에서 사용할 수 있게 되었다.

 

간단하게 계산기 로직을 설명하자면 hex값에서 투명도는 0~255의 값을 갖는다. 따라서 0~100%의 alpha값을 0~255로 변환하는 작업이 필요하고 이를 16진수의 값으로 변환하면 원하는 값이 나오게 된다.

예를 들어 10%를 입력하면 1A가 나와야한다. 그렇게 작성한 함수는 아래와 같다.

fun getAlphaCode(alphaPercent: Int): String {
    val decimal = (255 * (alphaPercent / 100.0)).roundToInt()
    return String.format("%02X", decimal)
}

 

ui를 작업을 시작하기 전에 위의 16진수의 hex값을 계산하는 함수가 제대로 동작하는지 검증해야했다. 그렇기 때문에 앱을 개발하면서 가장 신경썼던 부분은 테스트코드였다. 따라서 0~100의 퍼센트값을 넣었을때 계산된 hex값이 테이블과 동일한지 여부를 체크하는 테스트 코드를 아래와 같이 작성하였다.

class ColorAlphaUtilsKtTest {
    @Test
    fun percent_to_alphacode() {
        var percent = 0
        while (percent <= 100) {
            assertEquals(colorAlpha[percent], getAlphaCode(percent))
            percent += 1
        }
    }
}

 

val colorAlpha = mapOf(
    100 to "FF",
    99 to "FC",
    98 to "FA",
    97 to "F7",
    96 to "F5",
    95 to "F2",
    94 to "F0",
    93 to "ED",
    92 to "EB",
    ...
    0 to "00",
)

 

테스트 코드를 통과했다는 것을 확인한 후에는 ui부분을 작업하였다.

alpha값을 입력할 textfield와 output을 보여줄 textfield를 두 개를 두고 input이 변경될때 output이 계산되도록 작업했다

Column(
    modifier = Modifier.wrapContentSize(), verticalArrangement = Arrangement.spacedBy(10.dp)
) {
    Text(text = text, fontSize = 20.sp, fontWeight = FontWeight.Bold)
    TextField(
        value = inputAlpha,
        onValueChange = {
            inputAlpha = it
            inputAlpha.toIntOrNull()?.let { it1 -> output = getAlphaCode(it1) }
        },
        maxLines = 1,
        colors = TextFieldDefaults.textFieldColors(
            unfocusedIndicatorColor = Color.Transparent,
            disabledIndicatorColor = Color.Transparent,
            focusedIndicatorColor = Color.Transparent,
            errorIndicatorColor = Color.Transparent
        ),
        placeholder = {
            Text("alpha 0 ~ 100")
        },
        trailingIcon = {
            Text("%")
        }
    )
    TextField(
        value = output,
        onValueChange = { },
        maxLines = 1,
        colors = TextFieldDefaults.textFieldColors(
            unfocusedIndicatorColor = Color.Transparent,
            disabledIndicatorColor = Color.Transparent,
            focusedIndicatorColor = Color.Transparent,
            errorIndicatorColor = Color.Transparent
        ),
        readOnly = true
    )
}

 

처음에는 이렇게 개발이 끝나는줄 알았다......... 근데 앱을 실행시키니 윈도우 사이즈가 너무 컸다......

타협은 없다... 해결하자...라는 생각으로 window 사이즈를 설정하는 방법을 찾았다. 그리고 마침내 찾은 솔루션!!!

Adaptive Window size를 설정할 수 있는 방법이 있었다.

fun main() = application {
    Window(
        onCloseRequest = ::exitApplication,
        // window size를 Dp.Unspectified로 설정하면 창을 자동으로 조정해준다.
        state = rememberWindowState(width = Dp.Unspecified, height = Dp.Unspecified),
        title = "Alpha code",
        resizable = false
    ) {
        App()
    }
}

 

 

데스크톱 앱 패키지 만들기

이제 남은것은 패키징해서 언제든지 실행시켜서 사용할 수 있도록 데스크톱에 설치하는것뿐이었다.

다행히 프로젝트를 만들때 distribution format에 dmg가 포함되어있어서 별도로 build.gradle 파일을 수정할 필요는 없었다.

만약 플랫폼별 옵션을 설정해주고 싶다면 링크을 참고해서 작성하면 좋을 것 같다. 그리고 위의 링크를 참고하면 패키징 작업을 위한 Task를 확인할 수 있었는데 아래의 명령어를 입력하면 패키징된 이미지를 받을 수 있었다.

./gradlew packageDistributionForCurrentOS

 

그렇게 퍼센트만 입력하면 alpha hex값이 계산되는 앱이 완성되었다. 페이지 이동도 없는 너무 간단한 앱이지만 그래도 더이상 매번 인터넷을 서칭하지 않아도 되니 좋은 것 같다.

 

혹시나 전체 코드를 확인하고 싶으시다면 아래의 링크를 참고해주세요

https://github.com/nighttwo1/color-alpha-code

 

GitHub - nighttwo1/color-alpha-code: Calculate alpha percent to color code

Calculate alpha percent to color code. Contribute to nighttwo1/color-alpha-code development by creating an account on GitHub.

github.com

 

 

참고 문서

https://github.com/JetBrains/compose-multiplatform/blob/master/tutorials/Native_distributions_and_local_execution/README.md

https://github.com/JetBrains/compose-multiplatform/tree/master/tutorials/Window_API_new#adaptive-window-size

반응형