본문 바로가기
Android/Jetpack Compose App

JETPACK COMPOSE: 팁 계산기 만들기 - 1

by 개발자J의일상 2022. 1. 26.
반응형

 

앱을 만들기 전에 몇가지에 대해서 배워보겠습니다.

아래 코드는 jetpack으로 default Activity를 생성했을 때 만들어지는 코드입니다.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            JetTipAppTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    Greeting("Android")
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    JetTipAppTheme {
        Greeting("Android")
    }
}

JetTipAppTheme의 정체는 무엇일까요?

바로 ui.theme에 있는 @Composable function으로 content: @Composable을 매개변수로 받고 Unit를 return하는 함수입니다.

 

그럼 우리도 비슷하게 function을 만들면 동일한 동작을 하게 될까요?

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            JetTipAppTheme {
                MyApp {

                }
            }
        }
    }
}

@Composable
fun MyApp(content: @Composable () -> Unit) {
    // A surface container using the 'background' color from the theme
    Surface(color = MaterialTheme.colors.background) {
        Text("Hello Again!")
    }
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    JetTipAppTheme {
        MyApp {

        }
    }
}

@Composable function인 Myapp을 만들고 content로 @composable을 받아서 Unit를 반환하는 매개변수를 동일하게 만들어 줬습니다.

컴포저블은 일반적으로 content 컴포저블 람다(content: @Composable () -> Unit)를 사용합니다. 슬롯 API는 특정 용도를 위해 여러 content 매개변수를 노출합니다. 예를 들어 TopAppBar를 사용하면 title, navigationIcon 및 actions의 콘텐츠를 제공할 수 있습니다.

JetTipAppTheme에 있던 Surface와 Text를 MyApp으로 옮겨주고 Myapp { }을 수행시켜주면 동일하게 Hello Again!이 출력되는 것을 볼 수 있습니다.

 

 

이제 JetTipAppTheme을 MyApp안으로 옮겨봅시다.

JetTipAppTheme안에 Surface를 넣고 그 안에 MyApp에서 받은 content()를 호출해줍니다.

 

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApp {
                Text(text = "Hello Again!")
            }
        }
    }
}

@Composable
fun MyApp(content: @Composable () -> Unit) {
    JetTipAppTheme {
        // A surface container using the 'background' color from the theme
        Surface(color = MaterialTheme.colors.background) {
            content()
        }
    }
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    MyApp {
        Text(text = "Hello Again!")
    }
}

 

그대로 동일하게 Hello Again!이 출력 되는 것을 볼 수 있습니다.

 

 

 

우선 먼저 앱에 가장 위에 UI인 Total Per Person 부분부터 만들어 봅시다.

만들기 위해 Card를 사용할수도 있지만 우선 Surface로 만들어 봅시다.

빠르게 UI를 확인하기 위해 @Preview를 적어주고, Surface에 modifier를 선언하여 UI를 만들어 줍니다.

우선 적으로 넓이가 꽉찬 UI이므로 fillMaxWidth()를 해주고 height를 150.dp로 지정하여 네모 박스를 만듭니다.

이후 모서리 부분을 동그랗게 만들기 위해 .clip을 사용하는데 2가지 방법이 있습니다.

 

@Preview
@Composable
fun TopHeader() {
    Surface(modifier = Modifier
        .fillMaxWidth()
        .height(150.dp)
        //.clip(shape = RoundedCornerShape(corner = CornerSize(12.dp))) // [1]
        .clip(shape = CircleShape.copy(all = CornerSize(12.dp))) // [2]
    ) {

    }
}

 

모서리를 원으로 만드는 방법은 여러가지가 있습니다. [1]번은 RoundedCornerShape를 사용하였고 [2]번은 CircleShape.copy를 사용하였습니다. all을 하면 모든 모서리의 경우를 지정하는 것입니다.

 

두가지 방법 다 알아두면 좋을 것 같습니다.

둘다 결과는 동일합니다.

 

왼쪽 1번, 오른쪽 2번

 

이제 배경 color를 넣어봅시다!

 

@Preview
@Composable
fun TopHeader() {
    Surface(modifier = Modifier
        .fillMaxWidth()
        .height(150.dp)
        //.clip(shape = RoundedCornerShape(corner = CornerSize(12.dp)))
        .clip(shape = CircleShape.copy(all = CornerSize(12.dp))),
        color = Color(color=0xFFE9D7F7)
    ) {

    }
}

 

color = Color(color=0xFFE9D7F7)로 배경색을 지정해 주면 되는데 왼쪽에 line 숫자가 있는 곳에 네모 박스가 생기는데 눌러보면 Hex 값을 알려줍니다. 원하는 색을 찾아서 Hex값을 얻을 수 있습니다!

 

 

배경이 원하는 색으로 변경된 것을 볼 수 있습니다.

 

 

이제 Text를 넣어봅시다!

Text를 한줄씩 넣기 위해서는 Column을 사용해야 합니다!

기억이 안나시면 아래 링크를 다시 읽어보세요~

 

JETPACK COMPOSE: 터치하면 돈이 올라가는 앱을 만들어보자 - 1

 

JETPACK COMPOSE: 터치하면 돈이 올라가는 앱을 만들어보자 - 1

지난 시간 리뷰 Android studio 기본 예제로 알아보는 Jetpack Compose의 기초 Android studio 기본 예제로 알아보는 Jetpack Compose의 기초 What's Jetpack? A library of tools to help developers build moder..

mypark.tistory.com

@Preview
@Composable
fun TopHeader() {
    Surface(modifier = Modifier
        .fillMaxWidth()
        .height(150.dp)
        //.clip(shape = RoundedCornerShape(corner = CornerSize(12.dp)))
        .clip(shape = CircleShape.copy(all = CornerSize(12.dp))),
        color = Color(color=0xFFE9D7F7)
    ) {
        Column() {
            Text(text = "Total Per Person")
            Text(text = "$134")
        }
    }
}

 

Column() 안에 Text 두개를 넣어줍니다.

 

 

우리는 작성했던 Text가 각각 한줄씩 입력된 것을 볼 수 있습니다.

 

그런데 우리가 봤던 Text는 둘다 중앙에 있었는데요. 어떻게 해줘야 할까요?

바로 Column에 modifier를 지정하여 padding과 horizontalAlignment, verticalAlignment를 지정해주면 됩니다.

 

@Preview
@Composable
fun TopHeader() {
    Surface(modifier = Modifier
        .fillMaxWidth()
        .height(150.dp)
        //.clip(shape = RoundedCornerShape(corner = CornerSize(12.dp)))
        .clip(shape = CircleShape.copy(all = CornerSize(12.dp))),
        color = Color(color=0xFFE9D7F7)
    ) {
        Column(
            modifier = Modifier.padding(12.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Text(text = "Total Per Person")
            Text(text = "$134")
        }
    }
}

 

Surface안에 12.dp의 padding이 생겼고 거기에서 horizontal 방향으로 중앙에, vertical 방향으로 중앙에 Text가 위치하게 수정이 되었습니다.

 

 

이제 Text의 크기와 bold를 줘봅시다.

기억하는지 모르겠지만 Text안에 style을 주면 됩니다! bold를 주는 것은 fontWeight를 설정해주면 됩니다.

 

@Preview
@Composable
fun TopHeader() {
    Surface(modifier = Modifier
        .fillMaxWidth()
        .height(150.dp)
        //.clip(shape = RoundedCornerShape(corner = CornerSize(12.dp)))
        .clip(shape = CircleShape.copy(all = CornerSize(12.dp))),
        color = Color(color=0xFFE9D7F7)
    ) {
        Column(
            modifier = Modifier.padding(12.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Text(text = "Total Per Person",
                style = MaterialTheme.typography.h4)
            Text(text = "$134",
                style = MaterialTheme.typography.h4,
                fontWeight = FontWeight.ExtraBold)
        }
    }
}

 

이제 원하는데로 font의 크기와 bold가 지정된 것을 볼 수 있습니다.

 

 

$134는 사실 우리가 그냥 정해놓은 String을 출력하는 형태입니다.

하지만 우리가 원하는 것은 계산된 값을 출력하는 것입니다.

 

어떻게 해야 이 달러를 받아와서 출력할 수 있을까요?

TopHeader는 여기 Total Per Person과 달러를 출력하는 역할만 하는 function입니다.

 

그렇기 때문에 TopHeader를 호출하는 곳에 계산된 달러를 넣어서 그것을 받아와서 Text에서 출력을 하면 됩니다.

 

@Preview
@Composable
fun TopHeader(totalPerPerson: Double = 0.0) {
    Surface(modifier = Modifier
        .fillMaxWidth()
        .height(150.dp)
        //.clip(shape = RoundedCornerShape(corner = CornerSize(12.dp)))
        .clip(shape = CircleShape.copy(all = CornerSize(12.dp))),
        color = Color(color=0xFFE9D7F7)
    ) {
        Column(
            modifier = Modifier.padding(12.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Text(text = "Total Per Person",
                style = MaterialTheme.typography.h4)
            Text(text = "$$totalPerPerson",
                style = MaterialTheme.typography.h4,
                fontWeight = FontWeight.ExtraBold)
        }
    }
}

 

매개변수로 totalPerPerson을 Double로 받아오고 default를 0.0으로 초기화해 줍니다. 

초기화 하지않으면 $totalPerPerson의 값이 없어 @preview가 되지 않습니다.

Text의 string에 $totalPerPerson을 출력하도록 수정해주면 0.0이 출력되는 것을 볼 수 있습니다.

사실 저 "$"문자를 표시하기 위해 kotlin에서는 백슬래시를 특수문자 앞에 넣어주거나 따옴표를 3개 해줘야 출력이 되는데 여기서는 그냥 $를 작성해도 출력이 되는게 신기하긴 합니다.

 

물론 아래와 같이 작성해도 $가 출력되긴 합니다.

Text(text = """$$totalPerPerson""",

 

한가지 사소한거긴 하지만 소수점 2자리까지 표시하기 위해서 

totalPerPerson을 받아서 "%.2f"까지만 표시하도록 수정한 후 total에 저장하여 total을 출력하게 합니다.

 

@Preview
@Composable
fun TopHeader(totalPerPerson: Double = 0.0) {
    Surface(modifier = Modifier
        .fillMaxWidth()
        .height(150.dp)
        //.clip(shape = RoundedCornerShape(corner = CornerSize(12.dp)))
        .clip(shape = CircleShape.copy(all = CornerSize(12.dp))),
        color = Color(color=0xFFE9D7F7)
    ) {
        Column(
            modifier = Modifier.padding(12.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            val total = "%.2f".format(totalPerPerson)
            Text(text = "Total Per Person",
                style = MaterialTheme.typography.h4)
            Text(text = "$$total",
                style = MaterialTheme.typography.h4,
                fontWeight = FontWeight.ExtraBold)
        }
    }
}

 

소수점 두자리까지 출력되는 것을 확인할 수 있습니다.

 


이제 TopHeader 부분은 전부 만들었습니다.

 

다음시간에는 main 부분을 만들어보겠습니다. 

 

감사합니다.

300x250

댓글