imageUrl을 통해서 이미지를 불러올 것이기에 Coil 의존성을 추가
//1. coil 의존성 추가
implementation("io.coil-kt:coil:2.5.0")
//compose에서 사용하기위해서는 compose도 추가해야함
implementation("io.coil-kt:coil-compose:2.5.0")
mainfest에도 이미지를 불러오기위해서는 internet을 사용해야하기 때문에 internet permission 추가
<uses-permission android:name="android.permission.INTERNET"/>
card에 들어갈 데이터를 넣어주기 위해서 CardData라는 DataClass를 생성해준다.
data class CardData(
val imageUrl: String,
val imageDescription: String,
val name: String,
val description: String
)
CardData에는 imageUrl, imageDescription, name, description 총 4개의 변수들이 있다.
데이터는 Companion Object안에 한개만 만들었다.
companion object {
val cardData = CardData(
imageUrl = "https://picsum.photos/id/237/200/300",
imageDescription = "강아지 사진",
name = "unso99",
description = "unso99의 명함입니다."
)
}
샘플로 가져오는 이미지는 Lorem Picsum에서 가져왔으며 강아지 사진이다.
@Composable
fun CardEx(cardData: CardData) {
Card (
elevation = 8.dp,
modifier = Modifier.padding(8.dp)
) {
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(4.dp)
){
}
}
}
@Preview(showBackground = true)
@Composable
fun CardPreview() {
CardTheme {
Row{
CardEx(cardData = MainActivity.cardData)
}
}
}

Card를 전체적으로 Row로 감싸주면서 Card가 띄워져있는 효과를 주기 위해서 elevation을 추가하였다
Card 안에는 Row가 있으며 verticalAlignment를 통해서 수직으로 가운데가 되도록 설정하였다.
아직 Row안에 아무것도 없어서 작아보이지만 elevation을 통해 그림자 효과를 볼 수 있고, 가운데에 잘 정렬되어있는 것을 볼 수 있다.
@Composable
fun CardEx(cardData: CardData) {
Card(
elevation = 8.dp,
modifier = Modifier.padding(8.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(4.dp)
) {
// AsyncImage, Spacer, Column, Text로 레이아웃 구성
AsyncImage(
model = cardData.imageUrl, contentDescription = cardData.imageDescription,
modifier = Modifier.size(32.dp)
)
//적당한 공백을 위해 Spacer추가
Spacer(modifier = Modifier.size(8.dp))
Column {
Text(text = cardData.name)
Spacer(modifier = Modifier.size(4.dp))
Text(text = cardData.description)
}
}
}
}

이미지를 넣어주기 위해서 AsyncImage를 활용하였고, Modifier.size를 활용해 이미지의 크기를 조절하였다.
이름과 설명은 이미지 옆에 놓이면서 각각은 세로로 배치를 하기 위해 Column을 활용하였으며, 각각 요소들 사이에 공간을 주기위해 Spacer를 사용하였다.
@Composable
fun CardEx(cardData: CardData) {
val placeHolderColor = Color(0x33000000)
Card(
elevation = 8.dp,
modifier = Modifier.padding(8.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(4.dp)
) {
//AsyncImage에는 placeholder를 지정하고
//contentScale을 ContentScale.Crop으로 설정
//clip(CircleShape)로 둥근 외양설정
AsyncImage(
model = cardData.imageUrl, contentDescription = cardData.imageDescription,
contentScale = ContentScale.Crop,
placeholder = ColorPainter(placeHolderColor),
modifier = Modifier.size(32.dp)
.clip(CircleShape)
)
//적당한 공백을 위해 Spacer추가
Spacer(modifier = Modifier.size(8.dp))
Column {
Text(text = cardData.name)
Spacer(modifier = Modifier.size(4.dp))
Text(text = cardData.description)
}
}
}
}


image가 없을때 placeholder를 설정하여 회색배경을 적용했다.
이미지의 모양을 Modifier.clip을 통해 둥글게 설정 했으며, contentScale을 Crop으로 설정하여 가득차게 해주었다.
이렇게 간단하게 명함을 만들어보았다. 연습을 하면서도 아직 jetpack compose가 익숙하지 않기에 시간이 좀 걸리지만 크게 레이아웃을 짜고 하나씩 적용을 해보는 것도 좋은 방법인거 같다.
다음 포스트에서는 CheckBox에 대해서 다뤄볼 예정이다.
jetpack compose 연습 깃헙 링크
https://github.com/unso99/jetpack_compose_practice