Compose Basics

When to Use

  • When building new Android apps
  • When you want to write UI code in Kotlin
  • When you need a more modern approach to Android development
  • When you want to create responsive UIs that update automatically
Feature What It Does When to Use It
Declarative UI Describes what the UI should look like When you want to focus on the end result
Composable Functions Creates reusable UI components When you need to reuse UI elements
State Management Handles data changes automatically When your UI needs to update based on data
Layout System Arranges UI elements on screen When you need to position elements

A Few Examples

// Basic text display
fun Greeting() {
    Text("Hello, world!")//notice the text does not have brackets {..}
}

// Interactive button
fun Counter() {
    var count by remember { mutableStateOf(0) }
    
    Column {
        Text("Count: $count")
        Button(onClick = { count++ }) {
            Text("Increment")
        }
    }
}

// Layout with multiple elements
fun ProfileCard(name: String, role: String) {
    Column (modifier = Modifier.padding(16.dp))  // Notice the column here has (...) this is calling parameters
    //The curly braces here is a trailing lambda passed as the last paremeter of the function.  In Compose, that trailing lambda is the content block (sometimes called a content lambda or slot).
    {
        Text(name, style = MaterialTheme.typography.h5)
        Text(role, style = MaterialTheme.typography.body1)
        Button(onClick = { /* Handle click */ }) {  //notice the button does have brackets {...}
            Text("Contact")
        }
    }
}

What These Examples Are Doing

Here’s what each snippet does in plain terms:

  • Greeting: A minimal composable that only shows the text "Hello, world!" on the screen. There are no parameters and no child elements—just one Text call.
  • Counter: A small interactive example. It uses remember { mutableStateOf(0) } to keep a number in memory. The screen shows "Count: 0" (or whatever the current count is) and a button labeled "Increment." Each time you tap the button, count++ runs, the count updates, and Compose redraws the UI so the new number appears. This is a simple example of state driving the UI.
  • ProfileCard: A composable that takes a name and role as parameters. It puts them in a Column (so they stack vertically), with the name in a larger heading style and the role in body text, plus a "Contact" button at the bottom. So you can reuse the same card for different people by passing different names and roles.

Why Some Composables Use Brackets and Others Don't

The difference comes down to whether the composable can contain children:

Composables Without a Content Lambda → Just (...)

Text("Hello World")
  • Text doesn't expect child composables.
  • It just draws some text, and its parameters (text, modifier, style, etc.) are enough.
  • Therefore, you only pass arguments in parentheses.

Composables With a Content Lambda → (...){ ... }

Button(onClick = { /* do something */ }) {
            Text("Click Me")
        }
  • Button is a container composable.
  • It needs:
    • Parameters (like onClick) → go in the (...).
    • Child content (UI inside the button, like Text) → goes in the trailing { ... } lambda.
  • That trailing lambda is called the content slot or content lambda.

Why This Matters

Think of it like HTML:

  • Text(...) is like <span>Hello</span> → no nested tags.
  • Button(...){ ... } is like <button><span>Click Me</span></button> → it wraps other UI elements.

Compose vs. Traditional Android

When to Use

  • Use Compose for new projects or modernizing existing apps
  • Use traditional XML layouts when maintaining older apps
  • Use Compose when you want to write UI code in Kotlin
Approach What It Does When to Use It
Traditional (XML) Separates layout and logic For older Android apps
Compose Combines layout and logic For modern Android apps

Practical Examples

// Traditional XML approach
<TextView
    android:id="@+id/textView"
    android:text="Hello, world!"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
// Traditional Kotlin approach
val textView = findViewById<TextView>(R.id.textView)
textView.text = "Hello, world!"
// Compose approach
fun Greeting() {
    Text("Hello, world!")
}

What These Three Approaches Are Doing

All three snippets show "Hello, world!" on the screen, but in different ways:

  • Traditional XML: The first block is an XML layout file. It defines a TextView with an id and the text "Hello, world!". The layout and the text are declared in XML, separate from your Kotlin code.
  • Traditional Kotlin: The second block is Kotlin code that runs after the screen is built. It finds the TextView by its id (findViewById) and then sets its text. So you have two steps: define the UI in XML, then change it from Kotlin.
  • Compose approach: The third block is a Compose function. It describes the UI directly in Kotlin: when Greeting() is called, it draws a Text that says "Hello, world!". There is no separate XML file and no findViewById—just one function that builds the UI.