Fast Tutorial - Beautiful credit cards with JetPack Compose
Tags: java, android, uidesign, tutorial
Published: 2023-05-10 13:41:00

[_Shared from Danubius IT Solutions' techblog._](https://danubius.io/en/blog/fast-tutorial--beautiful-credit-cards)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31b7h1s75hhgp1xq68d3.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3c7myr8lf4v26wu1v75.png)