Jetpack Compose 1.8 rolls out handy features like Autofill integration, slick Text enhancements including auto-sizing and new overflow options, and efficient Visibility Tracking, alongside the usual performance boosts. Updating your dependencies brings faster UI and useful new tools to your Android development workflow.
Alright, let’s dive into the latest goodies Google has packed into Jetpack Compose with the 1.8 release (around April ’25). If you like your apps smooth and your coding life easier, pay attention!
Performance Keeps Getting Better
Google’s still tuning the engine! They’re reporting continued improvements in scroll performance and startup times compared to previous versions. Often, just updating the Compose BOM gets you these benefits.
// build.gradle.kts (Module level)
dependencies {
// Use the April '25 BOM for Compose 1.8 features
val composeBom = platform("androidx.compose:compose-bom:2025.04.01")
implementation(composeBom)
androidTestImplementation(composeBom)
// Core Compose dependencies (versions managed by BOM)
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.foundation:foundation") // Needed for BasicText, Autofill
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3") // Use latest M3
// Other dependencies...
}
These speed-ups come from ongoing optimizations in areas like text, input handling, lazy lists, and graphics, plus the continued refinement of the Modifier.Node
system.
Autofill Arrives in Compose
Tired of users manually typing login details or addresses? Compose 1.8 integrates with Android’s Autofill framework. Setting it up is pretty simple:
- Tell the system what the field is: Use
Modifier.semantics
with the rightContentType
. - Handle saving (if needed): Often automatic on navigation, or use
AutofillManager.commit()
explicitly (e.g., on button press).
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalAutofill
import androidx.compose.ui.platform.LocalAutofillTree
import androidx.compose.ui.semantics.contentType
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.input.ContentType
@Composable
fun LoginForm() {
val usernameState = remember { mutableStateOf("") }
val passwordState = remember { mutableStateOf("") }
val autofill = LocalAutofill.current
val autofillTree = LocalAutofillTree.current
// Register the fields within the Autofill tree
autofillTree += AutofillNode(
autofillTypes = listOf(AutofillType.Username),
onFill = { usernameState.value = it }
)
autofillTree += AutofillNode(
autofillTypes = listOf(AutofillType.Password),
onFill = { passwordState.value = it }
)
Column {
BasicTextField(
value = usernameState.value,
onValueChange = { usernameState.value = it },
modifier = Modifier
.semantics { contentType = ContentType.Username }
.autofill( // Connect node to field
autofillTypes = listOf(AutofillType.Username),
onFill = { usernameState.value = it }
)
)
BasicTextField(
value = passwordState.value,
onValueChange = { passwordState.value = it },
modifier = Modifier
.semantics { contentType = ContentType.Password }
.autofill(
autofillTypes = listOf(AutofillType.Password),
onFill = { passwordState.value = it }
)
)
Button(onClick = {
// Explicitly trigger save when user submits
autofill?.requestAutofillForNode(autofillTree.children.last())
// Or potentially commit if needed, check docs for specifics
// autofill?.commit()
}) {
Text("Login")
}
}
}
Check the official Autofill in Compose documentation for the full details.
Text Enhancements
Compose 1.8 brings some nice upgrades for text handling:
Auto-Sizing Text
Need text to shrink to fit its container? BasicText
(in androidx.compose.foundation
) now has an overload supporting autoSize
configuration. You can set min/max font sizes and the granularity (step size) for resizing. Material Text
support is expected to follow.
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.BasicText
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun AutoSizingTextDemo() {
Box(modifier = Modifier.size(width = 150.dp, height = 50.dp), contentAlignment = Alignment.Center) {
BasicText(
text = "This text might need to shrink",
style = TextStyle(
fontSize = 24.sp // Start size
),
autoSize = true,
minTextSize = 12.sp, // Smallest allowed size
maxTextSize = 24.sp, // Largest allowed size (matches initial style)
stepGranularity = 1.sp // How much to shrink each step
)
}
}
More Text Overflow Options
Beyond the classic end ellipsis (...
), you can now use TextOverflow.StartEllipsis
(...ext
) or TextOverflow.MiddleEllipsis
(Te...xt
) to truncate text differently.
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.sp
@Composable
fun OverflowDemo() {
val longText = "This is a very long piece of text that won't fit."
Column {
Text(longText, fontSize = 16.sp, maxLines = 1, overflow = TextOverflow.Ellipsis) // Default
Text(longText, fontSize = 16.sp, maxLines = 1, overflow = TextOverflow.StartEllipsis)
Text(longText, fontSize = 16.sp, maxLines = 1, overflow = TextOverflow.MiddleEllipsis)
}
}
Efficient Visibility Tracking
Need to know when a composable enters or leaves the screen, perhaps for analytics or triggering actions? The new Modifier.onLayoutRectChanged
(in androidx.compose.ui
) is a more performant way to do this than onGloballyPositioned
, especially inside lazy lists (LazyColumn
, LazyRow
). It allows debouncing and throttling callbacks to avoid excessive work during scrolling.
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onLayoutRectChanged
import androidx.compose.ui.unit.dp
@Composable
fun VisibilityTrackingList() {
LazyColumn {
items(100) { index ->
var isVisible by remember { mutableStateOf(false) }
Box(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.onLayoutRectChanged {
// isCompletelyVisible is true if the entire layout bounds are visible
// isVisible is true if any part is visible
val currentlyVisible = it.isVisible
if (currentlyVisible != isVisible) {
isVisible = currentlyVisible
println("Item $index visibility changed: $isVisible")
// Trigger analytics or other actions here
}
}
) {
Text("Item $index - Visible: $isVisible")
}
}
}
}
Modifier.Node: Custom Modifiers Done Right
Speaking of Modifier.Node
, it’s the modern way to build custom modifiers. If you were using Modifier.composed
, it’s time to look at the new guidance. It’s more efficient and gives you finer control.
Taming Stability
Sometimes Compose recompiles more than you’d like because it can’t tell if a class from an external library (or even your own code!) is ‘stable’. Compose Compiler 1.5.5+ (used with recent Compose versions) introduced a way to provide a configuration file listing classes you know are stable. This avoids unnecessary recompositions without needing wrapper classes. Check the stability configuration docs for the how-to.
Smarter Recomposition & Strong Skipping
The compiler’s getting smarter. It now generates more efficient code, sometimes skipping state tracking if a value is never read or only read once.
There’s also an experimental feature called “strong skipping mode” (aiming for stability around Compose 1.7/1.8). Normally, if a composable takes an ‘unstable’ parameter, it always recomposes if the parent does. Strong skipping relaxes this, allowing skips even with unstable params if the instance hasn’t changed. It also auto-remembers lambdas capturing unstable values. This makes Compose behave more like you’d intuitively expect, reducing recomposition surprises. You can experiment with it now.
Text Layout Tweaks: Bye-Bye Extra Padding
One subtle but impactful change (default since Jan ’24 / Compose 1.6+) is includeFontPadding
now being false
by default for Text
composables. This legacy setting added extra space above/below text based on font metrics. Turning it off makes Compose text align better with designs from tools like Figma right out of the box. Be aware this might cause small shifts in your UI and screenshot tests after updating!
@Composable
fun MyTextComponent(text: String) {
Text(
text = text,
// includeFontPadding = false // This is now the default!
style = MaterialTheme.typography.bodyLarge
)
}
If you relied on that old padding, you might need to add manual padding modifiers.
What Else?
- Material 3: Continues to get updates. Check the M3 release notes for the latest.
- Tooling: Android Studio keeps improving Compose previews and diagnostics.
- Compose Multiplatform: Keep an eye on Compose Multiplatform for desktop, iOS, and web capabilities, often aligning with Jetpack Compose features.
Keep Your Project Updated
To grab these goodies, keep your Compose dependencies fresh using the BOM.
// build.gradle.kts (Module level)
android {
// ...
buildFeatures {
compose = true
}
composeOptions {
// Verify compatible Kotlin compiler extension version for BOM 2025.04.01
kotlinCompilerExtensionVersion = "1.5.15" // Example, check official docs!
}
kotlinOptions {
jvmTarget = "1.8" // Or higher
}
}
dependencies {
val composeBom = platform("androidx.compose:compose-bom:2025.04.01")
implementation(composeBom)
// ... other compose dependencies
}
For more tips on performance, check out guides like this Compose Multiplatform Performance Guide.
Staying updated means better, faster apps. Happy composing!