DEV Community

Cover image for Fast Tutorial - Beautiful credit cards with JetPack Compose
Danubius IT Solutions
Danubius IT Solutions

Posted on • Edited on • Originally published at danubius.io

2

Fast Tutorial - Beautiful credit cards with JetPack Compose

Shared from Danubius IT Solutions' techblog.

This fast tutorial shows how to create a list of credit cards with JetPack Compose. Just follow the steps and try out Google’s declarative UI framework today!

Prerequisites

  • Latest version of Android Studio
  • JDK 11 or higher
  • Physical or virtual device for testing

Anatomy

Card example

The idea is very simple: Create a card, add a mesh gradient image, put over a box layout and take the parts to the right places. The key is the Box layout. With this composable, you can put elements in the 4 corners of the box. See the reference docs for more about Box layout.

Prepare

First of all, create a new Android Project and select Empty Compose Activity. Then clean up the sample code.

Get the image and font resources:

  • Visa logo
  • MasterCard logo
  • Space Mono font
  • Space Grotesk font
  • Some mesh gradients

Put image resources to /res/drawable.

Create a new resource folder for fonts: /res/font and copy font files (Space Grotesk bold for cardholder name and Space mono regular for card number).

Create CreditCard() composable

Create a new Kotlin file under the ui package and name it CreditCard.kt. Start a new composable function and add empty Card() component:

@Composable
fun CreditCard() {
Card(
modifier = Modifier
.height(200.dp),
shape = RoundedCornerShape(8.dp),
elevation = 8.dp
) { }
}

Add Image() inside card content for the mesh background:

@Composable
fun CreditCard(cardInfo: CardInfo) {
Card(
modifier = Modifier
.height(200.dp),
shape = RoundedCornerShape(8.dp),
elevation = 8.dp
) {
Image(
painter = painterResource(id = R.drawable.card_mesh),
contentDescription = "Card Background",
contentScale = ContentScale.FillBounds
)
}
}

The FillBounds content scale will expand the image to match the size of the card.

After the image, put a new Box() layout with some padding:

Box(modifier = Modifier.padding(16.dp)) { }
Add Image() to the Box TopStart position and load the Visa logo.
Box(modifier = Modifier.padding(16.dp)) {
Image(
painter = painterResource(id = R.drawable.visa),
contentDescription = "Visa",
modifier = Modifier
.width(86.dp)
.align(Alignment.TopStart)
)
}

Prepare the font faces to use for card number and cardholder texts. Open ui/theme/Type.kt and create new font families:

val SpaceMono = FontFamily(
Font(R.font.space_mono_regular)
)
val SpaceGrotesk = FontFamily(
Font(R.font.space_grotesk_bold, FontWeight.Bold)
)

Now you can use them in other composables.

To align the card number and the cardholder name under each other, we will use a Column() wrapper component and put the Text() inside it.

Box(modifier = Modifier.padding(16.dp)) {
Image(
painter = painterResource(id = R.drawable.visa),
contentDescription = "Visa",
modifier = Modifier
.width(86.dp)
.align(Alignment.TopStart)
)
Column(modifier = Modifier
.align(Alignment.BottomStart)) {
Text(
text = "5435 9876 1234 6543",
fontFamily = SpaceMono,
letterSpacing = 1.2.sp,
fontSize = 16.sp
)
Text(
text = cardInfo.cardHolder,
fontFamily = SpaceGrotesk,
letterSpacing = 1.1.sp,
fontSize = 16.sp
)
}
}

Showtime

The CreditCard() composable is ready to use, put inside your app component:

@Composable
fun DiCardApp() {
DanubiusCreditCardTheme {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
CreditCard(cardInfo = CardInfo(
backgroundDrawable = R.drawable.card_mesh,
providerDrawable = R.drawable.mc,
cardNumber = "8547 9658 6325 4521",
cardHolder = "John Fluffy"
))
}
}
}

More than one

Create a new data class to hold the attributes of a CreditCard() composable, for example CardInfo.kt.

data class CardInfo(
val cardNumber: String,
val cardHolder: String,
val providerDrawable: Int,
val backgroundDrawable: Int
)

Create a fake list of cards:

val cards = listOf(
CardInfo(
backgroundDrawable = R.drawable.card_mesh,
providerDrawable = R.drawable.mc,
cardNumber = "8547 9658 6325 4521",
cardHolder = "Jim Hopper"
),
CardInfo(
backgroundDrawable = R.drawable.card_mesh_2,
providerDrawable = R.drawable.visa,
cardNumber = "6582 4521 3256 8522",
cardHolder = "Steve Harrington"
),
CardInfo(
backgroundDrawable = R.drawable.card_mesh_3,
providerDrawable = R.drawable.visa,
cardNumber = "9856 7452 2569 7413",
cardHolder = "Joyce Byers"
)
)

Change Column() component to LazyColumn() and load the items of cards list.

LazyColumn(
modifier = Modifier
.fillMaxHeight()
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
items(cards) { card ->
CreditCard(cardInfo = card)
}
}

Refactor the CardInfo component to display CardInfo object attributes. See the final implementation below:

@Composable
fun CreditCard(cardInfo: CardInfo) {
Card(
modifier = Modifier
.height(200.dp),
shape = RoundedCornerShape(8.dp),
elevation = 8.dp
) {
Image(
painter = painterResource(id = cardInfo.backgroundDrawable),
contentDescription = "Card Background",
contentScale = ContentScale.FillBounds
)
Box(modifier = Modifier.padding(16.dp)) {
Image(
painter = painterResource(id = cardInfo.providerDrawable),
contentDescription = "Visa",
modifier = Modifier
.width(86.dp)
.align(Alignment.TopStart)
)
Column(modifier = Modifier.align(Alignment.BottomStart)) {
Text(
text = cardInfo.cardNumber,
fontFamily = SpaceMono,
letterSpacing = 1.2.sp,
fontSize = 16.sp
)
Text(
text = cardInfo.cardHolder,
fontFamily = SpaceGrotesk,
letterSpacing = 1.1.sp,
fontSize = 16.sp
)
}
}
}
}

That’s it! You can play around with other backgrounds, fonts, and layouts. You can find the full example on GitHub in this repository. Don’t forget to ⭐️ the repository.

Final results

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Retry later