Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Building an Account Summary Screen with Balance and Transactions

Hello! You’ve already built banking interface elements and used previews to inspect them in different conditions. Now you’ll assemble those pieces into the first complete screen of the course: a static account summary with a balance card and a short recent-transactions section.

“Static” is an important boundary here. The amounts and transactions will be clearly marked sample values, not data from an account or an API. The goal is a screen you can preview and run, with a structure you can keep when you add real behavior later. Allow about 40 minutes to read, implement, and inspect it.


Design the screen as a composition of parts

A screen is easier to change when its main function describes the layout rather than containing every detail of every row. We’ll use one composable for the whole screen, one for the balance card, and one for a transaction row. Your existing AccountBalance composable will supply the account name and amount inside the card.

For a quick look at assembling repeated content, watch these short portions of Jetpack Compose basics code-along from Android Developers. The example uses greetings rather than transactions; focus on how a parent places several reusable items and how width and padding affect the result.

Jetpack Compose basics code-along

Watch the selected portions of Jetpack Compose basics code-along by Android Developers for the layout decisions we’ll apply to the account screen.

In repeated items, notice how a parent creates one composable per sample value. Then watch width and spacing, paying attention to where full-width and padding modifiers are placed. Stop before the button example; this screen has no controls yet.

The balance needs a visual container. Read the filled-card example in the Android Developers Card guide before writing it.

Card  |  Jetpack Compose  |  Android Developers

Read the filled-card example to see how a Material 3 Card contains other composables and takes its container color from the theme.

Under “Advanced implementations,” find the subsection “Filled card.” Read the filled example, including its code. Notice that the example fixes the card’s size; our screen will instead let the card fill the available width.

Neither the card nor its color has to be invented from scratch. What makes this your screen is the arrangement: a heading, a balance card, then transaction rows that can accommodate descriptions and signed amounts.


Build the account summary

Add the following to the Kotlin file containing your existing AccountBalance composable. Keep its earlier definition; the code below calls it. If you place the new screen in another file, make sure AccountBalance is visible there and import it as needed.

These are the imports used by the new code. Android Studio can add any that your file does not already have.

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp

Start with a small representation of what each displayed row needs. The list is fixed sample content for this module.

private data class SummaryTransaction(
    val description: String,
    val date: String,
    val amountText: String
)

private val sampleTransactions = listOf(
    SummaryTransaction("Groceries", "12 Mar", "-USD 32.40"),
    SummaryTransaction("Pay deposit", "10 Mar", "+USD 1,850.00"),
    SummaryTransaction("Transport", "8 Mar", "-USD 18.75")
)

amountText is deliberately a string: it is already display text for a mock screen. Do not use these strings for calculations or treat them as a way to model money in a banking system. That distinction will matter when you build the backend and, later, format amounts for a user’s locale.

Now add the screen and its two smaller components:

@Composable
fun AccountSummaryScreen(modifier: Modifier = Modifier) {
    Surface(
        modifier = modifier.fillMaxSize(),
        color = MaterialTheme.colorScheme.background
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .verticalScroll(rememberScrollState())
                .padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(16.dp)
        ) {
            Text(
                text = "Account summary",
                style = MaterialTheme.typography.headlineMedium
            )

            SummaryBalanceCard(modifier = Modifier.fillMaxWidth())

            Text(
                text = "Recent transactions",
                style = MaterialTheme.typography.titleLarge
            )

            Column {
                sampleTransactions.forEachIndexed { index, transaction ->
                    SummaryTransactionRow(transaction)

                    if (index < sampleTransactions.lastIndex) {
                        HorizontalDivider()
                    }
                }
            }
        }
    }
}

@Composable
private fun SummaryBalanceCard(modifier: Modifier = Modifier) {
    Card(
        modifier = modifier,
        colors = CardDefaults.cardColors(
            containerColor = MaterialTheme.colorScheme.surfaceVariant
        )
    ) {
        Column(
            modifier = Modifier.padding(20.dp),
            verticalArrangement = Arrangement.spacedBy(12.dp)
        ) {
            Text(
                text = "Available balance",
                style = MaterialTheme.typography.labelLarge,
                color = MaterialTheme.colorScheme.onSurfaceVariant
            )

            AccountBalance(
                accountName = "Checking",
                balanceText = "USD 4,280.50",
                modifier = Modifier.fillMaxWidth()
            )
        }
    }
}

@Composable
private fun SummaryTransactionRow(transaction: SummaryTransaction) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 12.dp),
        horizontalArrangement = Arrangement.spacedBy(12.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Column(modifier = Modifier.weight(1f)) {
            Text(
                text = transaction.description,
                style = MaterialTheme.typography.bodyLarge,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis
            )
            Text(
                text = transaction.date,
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant
            )
        }

        Text(
            text = transaction.amountText,
            style = MaterialTheme.typography.bodyMedium
        )
    }
}

Read the parent AccountSummaryScreen from top to bottom: its composables appear in the same order as the screen’s sections. The card’s Column keeps “Available balance” above your existing account-and-amount element. In each transaction Row, the description-and-date column has weight(1f), so it uses the space left after the amount is measured. A long description can shorten with an ellipsis instead of pushing the amount out of view.

There are only three transactions, so a regular Column and a loop are appropriate here. The outer verticalScroll makes the whole screen scroll if a smaller display or larger text needs more height. A long, changing transaction history will call for a different list approach later; it is not necessary to introduce it for this fixed sample.

If you already made a TransactionRow with the information and layout you want, you can use it in place of SummaryTransactionRow. Keep the screen’s section structure and pass values that match your existing row’s parameters; there is no need to retain two near-identical row components.


Make it the screen you preview and run

In MainActivity.setContent, keep your existing app theme and replace the call that displays BankingSample() with AccountSummaryScreen(). You do not need a second theme wrapper around the card; the theme surrounding the screen supplies its colors and typography.

Add a full-screen preview beside your earlier previews. Replace YourProjectTheme with the theme composable your project actually uses, just as you did in the previous lesson.

import androidx.compose.ui.tooling.preview.Preview

@Preview(
    name = "Account summary",
    widthDp = 360,
    heightDp = 720,
    showBackground = true
)
@Composable
private fun AccountSummaryPreview() {
    YourProjectTheme {
        AccountSummaryScreen()
    }
}

Refresh the preview, then run the app on your emulator. You should see the heading, a full-width balance card, a “Recent transactions” heading, and three separated rows. Scroll on the emulator to confirm the bottom of the screen remains reachable.

Inspect the result rather than treating a successful build as the finish line. In particular, check that:

  • the balance is legible inside the card and does not collide with “Checking”;
  • every transaction amount remains visible beside its description;
  • the last row can be reached at a smaller screen height or larger font size;
  • the theme looks sensible in the light and dark previews you set up previously.

Your earlier long-account preview may already have revealed that AccountBalance becomes crowded. The short “Checking” label makes this sample screen workable, but it does not resolve that broader layout issue. If the account and balance collide even here, adjust that reusable composable rather than hiding the problem with more card padding.


What you’ve completed

You now have a runnable, static account-summary screen assembled from reusable Compose parts. A themed Card distinguishes the balance, while rows and dividers make a small set of recent transactions readable. The sample values are presentation data only, and the preview and emulator give you two ways to inspect the result.

This completes the first module’s interface. In the next module, you’ll make screens interactive, beginning with how a change in state causes Compose to update what you see.

Can't find a good explanation? Sign up and we'll make it for you

Sign up