What’s new in the Jetpack Compose August ’25 release

What’s new in the Jetpack Compose August ’25 release

Home » News » What’s new in the Jetpack Compose August ’25 release
Table of Contents

Posted by Meghan Mehta – Developer Relations Engineer and Nick Butcher – Product Supervisor

At the moment, the Jetpack Compose August ‘25 launch is steady. This launch comprises model 1.9 of core compose modules (see the total BOM mapping), introducing new APIs for rendering shadows, 2D scrolling, wealthy styling of textual content transformations, improved checklist efficiency, and extra!

To make use of at present’s launch, improve your Compose BOM model to 2025.08.00:

implementation(platform("androidx.compose:compose-bom:2025.08.00"))

Shadows

We’re blissful to introduce two extremely requested modifiers: Modifier.dropShadow() and Modifier.innerShadow() permitting you to render box-shadow results (in comparison with the present Modifier.shadow() which renders elevation primarily based shadows primarily based on a lighting mannequin).

Modifier.dropShadow()

The dropShadow() modifier attracts a shadow behind your content material. You may add it to your composable chain and specify the radius, coloration, and unfold. Keep in mind, content material that ought to seem on prime of the shadow (like a background) must be drawn after the dropShadow() modifier.

@Composable
@Preview(showBackground = true)
enjoyable SimpleDropShadowUsage() {
    val pinkColor = Colour(0xFFe91e63)
    val purpleColor = Colour(0xFF9c27b0)
    Field(Modifier.fillMaxSize()) {
        Field(
            Modifier
                .dimension(200.dp)
                .align(Alignment.Middle)
                .dropShadow(
                    RoundedCornerShape(20.dp),
                    dropShadow = DropShadow(
                        15.dp,
                        coloration = pinkColor,
                        unfold = 10.dp,
                        alpha = 0.5f
                    )
                )
                .background(
                    purpleColor,
                    form = RoundedCornerShape(20.dp)
                )
        )
    }
}

drop shadow drawn all around shape

Determine 1. Drop shadow drawn throughout form

Modifier.innerShadow()

The Modifier.innerShadow() attracts shadows on the inset of the offered form:

@Composable
@Preview(showBackground = true)
enjoyable SimpleInnerShadowUsage() {
    val pinkColor = Colour(0xFFe91e63)
    val purpleColor = Colour(0xFF9c27b0)
    Field(Modifier.fillMaxSize()) {
        Field(
            Modifier
                .dimension(200.dp)
                .align(Alignment.Middle)
                .background(
                    purpleColor,
                    form = RoundedCornerShape(20.dp)
                )
                .innerShadow(
                    RoundedCornerShape(20.dp),
                    innerShadow = InnerShadow(
                        15.dp,
                        coloration = Colour.Black,
                        unfold = 10.dp,
                        alpha = 0.5f
                    )
                )
        )
    }
}

modifier.innerShadow() applied to a shape

Determine 2. Modifier.innerShadow() utilized to a form

The order for inside shadows is essential. The inside shadow attracts on prime of the content material, so for the instance above, we wanted to maneuver the inside shadow modifier after the background modifier. We’d have to do one thing comparable when utilizing it on prime of one thing like an Picture. On this instance, we’ve positioned a separate Field to render the shadow within the layer above the picture:

@Composable
@Preview(showBackground = true)
enjoyable PhotoInnerShadowExample() {
    Field(Modifier.fillMaxSize()) {
        val form = RoundedCornerShape(20.dp)
        Field(
            Modifier
                .dimension(200.dp)
                .align(Alignment.Middle)
        ) {
            Picture(
                painter = painterResource(id = R.drawable.cape_town),
                contentDescription = "Picture with Inside Shadow",
                contentScale = ContentScale.Crop,
                modifier = Modifier.fillMaxSize()
                    .clip(form)
            )
            Field(
                modifier = Modifier.fillMaxSize()
                    .innerShadow(
                        form,
                        innerShadow = InnerShadow(15.dp,
                            unfold = 15.dp)
                    )
            )
        }
    }
}

Inner shadow on top of an image

Determine 3.Inside shadow on prime of a picture

New Visibility modifiers

Compose UI 1.8 launched onLayoutRectChanged, a brand new performant strategy to monitor the situation of parts on display screen. We’re constructing on prime of this API to assist widespread use circumstances by introducing onVisibilityChanged and onFirstVisible. These APIs settle for elective parameters for the minimal fraction or period of time the merchandise has been seen for earlier than invoking your motion.

Use onVisibilityChanged for UI adjustments or negative effects that ought to occur primarily based on visibility, like routinely taking part in and pausing movies or beginning an animation:

LazyColumn {
  objects(feedData) { video ->
    VideoRow(
        video,
        Modifier.onVisibilityChanged(minDurationMs = 500, minFractionVisible = 1f) {
          seen ->
            if (seen) video.play() else video.pause()
          },
    )
  }
}

Use onFirstVisible to be used circumstances once you want to react to a component first changing into seen on display screen for instance to log impressions:

LazyColumn {
    objects(100) {
        Field(
            Modifier
                // Log impressions when merchandise has been seen for 500ms
                .onFirstVisible(minDurationMs = 500) { /* log impression */ }
                .clip(RoundedCornerShape(16.dp))
                .drawBehind { drawRect(backgroundColor) }
                .fillMaxWidth()
                .peak(100.dp)
        )
    }
}

Wealthy styling in OutputTransformation

BasicTextField now helps making use of types like coloration and font weight from inside an OutputTransformation.

The brand new TextFieldBuffer.addStyle() strategies allow you to apply a SpanStyle or ParagraphStyle to vary the looks of textual content, with out altering the underlying TextFieldState. That is helpful for visually formatting enter, like cellphone numbers or bank cards. This methodology can solely be referred to as inside an OutputTransformation.

// Format a cellphone quantity and coloration the punctuation
val phoneTransformation = OutputTransformation {
    // 1234567890 -> (123) 456-7890
    if (size == 10) {
        insert(0, "(")
        insert(4, ") ")
        insert(9, "-")

        // Colour the added punctuation
        val grey = Colour(0xFF666666)
        addStyle(SpanStyle(coloration = grey), 0, 1)
        addStyle(SpanStyle(coloration = grey), 4, 5)
        addStyle(SpanStyle(coloration = grey), 9, 10)
    }
}

BasicTextField(
    state = myTextFieldState,
    outputTransformation = phoneTransformation
)

LazyLayout

The constructing blocks of LazyLayout are all now steady! Take a look at LazyLayoutMeasurePolicy, LazyLayoutItemProvider, and LazyLayoutPrefetchState to construct your personal Lazy parts.

Prefetch Enhancements

There at the moment are vital scroll efficiency enhancements in Lazy Record and Lazy Grid with the introduction of latest prefetch conduct. Now you can outline a LazyLayoutCacheWindow to prefetch extra content material. By default, just one merchandise consists forward of time within the path of scrolling, and after one thing scrolls off display screen it’s discarded. Now you can customise the quantity of things forward to prefetch and behind to retain by means of a fraction of the viewport or dp dimension. If you choose into utilizing LazyLayoutCacheWindow, objects start prefetching within the forward space immediately.

The configuration entry level for that is on LazyListState, which takes within the cache window dimension:

@OptIn(ExperimentalFoundationApi::class)
@Composable
personal enjoyable LazyColumnCacheWindowDemo() {
    // Prefetch objects 150.dp forward and retain objects 100.dp behind the seen viewport
    val dpCacheWindow = LazyLayoutCacheWindow(forward = 150.dp, behind = 100.dp)
    // Alternatively, prefetch/retain objects as a fraction of the checklist dimension
    // val fractionCacheWindow = LazyLayoutCacheWindow(aheadFraction = 1f, behindFraction = 0.5f)
    val state = rememberLazyListState(cacheWindow = dpCacheWindow)
    LazyColumn(state = state) {
        objects(1000) { Textual content(textual content = "$it", fontSize = 80.sp) }
    }
}

lazylayout in Compose 1.9 release

Word: Prefetch composes extra objects than are at present seen — the brand new cache window API will seemingly improve prefetching. Because of this merchandise’s LaunchedEffects and DisposableEffects might run earlier – don’t use this as a sign for visibility e.g. for impression monitoring. As a substitute, we suggest utilizing the brand new onFirstVisible and onVisibilityChanged APIs. Even when you’re not manually customizing LazyLayoutCacheWindow now, keep away from utilizing composition results as a sign of content material visibility, as this new prefetch mechanism will probably be enabled by default in a future launch.

Scroll

2D Scroll APIs

Following the discharge of Draggable2D, Scrollable2D is now accessible, bringing two-dimensional scrolling to Compose. Whereas the present Scrollable modifier handles single-orientation scrolling, Scrollable2D permits each scrolling and flinging in 2D. This lets you create extra advanced layouts that transfer in all instructions, corresponding to spreadsheets or picture viewers. Nested scrolling can also be supported, accommodating 2D eventualities.

val offset = bear in mind { mutableStateOf(Offset.Zero) }
Field(
    Modifier.dimension(150.dp)
        .scrollable2D(
            state =
                rememberScrollable2DState { delta ->
                    offset.worth = offset.worth + delta // replace the state
                    delta // point out that we consumed all of the pixels accessible
                }
        )
        .background(Colour.LightGray),
    contentAlignment = Alignment.Middle,
) {
    Textual content(
        "X=${offset.worth.x.roundToInt()} Y=${offset.worth.y.roundToInt()}",
        type = TextStyle(fontSize = 32.sp),
    )
}

moving image of 2D scroll API demo

Scroll Interop Enhancements

There are bug fixes and new options to enhance scroll and nested scroll interop with Views, together with the next:

    • Fastened the dispatching of incorrect velocities throughout fling animations between Compose and Views.
    • Compose now appropriately invokes the View’s nested scroll callbacks within the applicable order.

Enhance crash evaluation by including supply data to stack traces

Now we have heard from you that it may be onerous to debug Compose crashes when your personal code doesn’t seem within the stack hint. To deal with this we’re offering a brand new, opt-in API to supply richer crash location particulars, together with composable names and places enabling you to:

    • Effectively determine and resolve crash sources.
    • Extra simply isolate crashes for reproducible samples.
    • Examine crashes that beforehand solely confirmed inner stack frames.

Word that we don’t suggest utilizing this API in launch builds as a result of efficiency impression of amassing this further data, nor does it work in minified apks.

To allow this function, add the road under to the applying entry level. Ideally, this configuration must be carried out earlier than any compositions are created to make sure that the stack hint data is collected:

class App : Software() {
   override enjoyable onCreate() {
        // Allow just for debug taste to keep away from perf regressions in launch
        Composer.setDiagnosticStackTraceEnabled(BuildConfig.DEBUG)
   }
}

New annotations and Lint checks

We’re introducing a brand new runtime-annotation library that exposes annotations utilized by the compiler and tooling (corresponding to lint checks). This enables non-Compose modules to make use of these annotations and not using a dependency on the Compose runtime library. The @Steady, @Immutable, and @StableMarker annotations have moved to runtime-annotation, permitting you to annotate courses and capabilities that don’t rely upon Compose.

Moreover, we’ve got added two new annotations and corresponding lint checks:

    • @RememberInComposition: An annotation that may mark constructors, capabilities, and property getters, to point that they have to not be referred to as straight inside composition with out being remembered. Errors will probably be raised by a corresponding lint examine.
    • @FrequentlyChangingValue: An annotation that may mark capabilities, and property getters, to point that they shouldn’t be referred to as straight inside composition, as this will trigger frequent recompositions (for instance, marking scroll place values and animating values). Warnings are offered by a corresponding lint examine.

Extra updates

    • To simplify compatibility and enhance stability for lint examine assist, Compose now requires Android Gradle Plugin (AGP) / Lint model 8.8.2 or greater. Take a look at this new documentation web page to study extra.
    • Two new APIs have been added for context menus:

Get began

We respect all bug studies and have requests submitted to our challenge tracker. Your suggestions permits us to construct the APIs you want in your apps. Pleased composing!

Supply hyperlink

author avatar
roosho Senior Engineer (Technical Services)
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog. 

share this article.

Enjoying my articles?

Sign up to get new content delivered straight to your inbox.

Please enable JavaScript in your browser to complete this form.
Name