jetpack compose 1.8 autofill, text, visibility & more
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!
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.
Tired of users manually typing login details or addresses? Compose 1.8 integrates with Android’s Autofill framework. Setting it up is pretty simple:
Modifier.semantics
with the right ContentType
.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.
Compose 1.8 brings some nice upgrades for text handling:
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
)
}
}
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)
}
}
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")
}
}
}
}
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.
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.
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.
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.
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!
Introduction: Transform Your Cross-Platform Development with Material Design 3 Are you ready to revolutionize your… Read More
Reified Keyword in Kotlin: Simplify Your Generic Functions Kotlin's reified keyword lets your generic functions know the… Read More
Android Studio Cloud: Ditch the Setup, Code Anywhere (Seriously!) Alright, fellow Android devs, gather 'round… Read More