Yum News Yum News

Technology  ·  Artificial Intelligence  ·  Developer Insights

Breaking
Gemini Task Automation Guide: India UK Japan Apps ✦   How to Set Up ChatGPT Wallet for Agent Purchases ✦   How to Set Up and Use Gemini Live on Apple CarPlay ✦   How to Set Up Gemini Live on Apple CarPlay ✦   How to Use the Gemini Decisions API for Fast Choices ✦   How to Use Gemini Task Automation on Pixel Phones   ✦   Gemini 3.8 Live launches with native audio dialogue  ✦  Android September Drop adds Find Hub memory  ✦  ML Kit now supports Gemini Nano on-device inference
How to Build Adaptive Layouts with mediaQuery in Jetpack Compose
androidtutorialshow-to

How to Build Adaptive Layouts with mediaQuery in Jetpack Compose

Use the mediaQuery API in Jetpack Compose to create layouts that adapt to window posture, size, pointer precision, and viewing distance on phones, foldables, and larger screens.

Android apps now run on phones, foldables, tablets, Googlebooks, and more. Hard-coded checks for device type break when users resize windows or fold a device. The mediaQuery API in Jetpack Compose gives a declarative way to query window and device capabilities and update layouts accordingly.

This guide shows how to enable the API, query posture and size, and combine it with other adaptive tools. You can pair it with Grid layouts covered in our Compose Grid named areas guide.

Enable mediaQuery in your app

The API is experimental and off by default. Enable it early in your Application class:

class MyApplication : Application() {
    override fun onCreate() {
        ComposeUiFlags.isMediaQueryIntegrationEnabled = true
        super.onCreate()
    }
}

Opt into the experimental API with @OptIn(ExperimentalMediaQueryApi::class) on composables that use it. After this, mediaQuery and derivedMediaQuery become available.

Adaptive device screens showing different layouts

Query window posture for foldables

Foldable devices support flat, book, and tabletop postures. Use mediaQuery to switch layouts when the user folds the device.

@OptIn(ExperimentalMediaQueryApi::class)
@Composable
fun VideoPlayer() {
    when {
        mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> {
            // Content on top, controls on bottom across the hinge
            TabletopLayout()
        }
        mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> {
            BookLayout()
        }
        else -> {
            FlatLayout()
        }
    }
}

The UiMediaScope provides windowPosture. The query recomposes when the posture changes. Official docs recommend this for media players and dual-pane content that benefits from the physical fold.

Adapt to window size classes

Window width and height update frequently during resizing. Prefer derivedMediaQuery for these values to avoid unnecessary recompositions.

val narrowerThanMedium by derivedMediaQuery {
    windowWidth < WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND.dp
}
val narrowerThanExpanded by derivedMediaQuery {
    windowWidth < WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND.dp
}

when {
    narrowerThanMedium -> SinglePaneLayout()
    narrowerThanExpanded -> TwoPaneLayout()
    else -> ThreePaneLayout()
}

This matches Android’s recommended window size class breakpoints. The layout expands as the window grows without checking for “isTablet”.

Handle pointer precision and keyboard type

Touch targets need to be larger when the primary pointer has low precision. Query pointerPrecision:

if (mediaQuery { pointerPrecision == UiMediaScope.PointerPrecision.Blunt }) {
    LargeTouchButton()
} else {
    CompactButton()
}

Precision values range from Fine (mouse) to Coarse/Blunt (touch). The highest available precision is reported when multiple devices are connected.

For keyboards:

if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) {
    SuggestPhysicalKeyboard()
}

This helps desktop-class experiences on Googlebook or when a keyboard is attached.

Adjust for viewing distance and hardware features

Viewing distance estimates how far the user is from the screen. Increase text and targets for Far or Medium distances, common on TVs or when a phone is used at arm’s length.

val fontSize = when {
    mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Far } -> 20.sp
    mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Medium } -> 18.sp
    else -> 16.sp
}

You can also gate features:

if (mediaQuery { hasMicrophone }) {
    MicButton()
}
if (mediaQuery { hasCamera }) {
    CameraButton()
}

Developer workspace with multiple devices

Combine with Grid for structured adaptive UIs

mediaQuery works well as the decision layer for Grid configurations. Define different Grid configs and select them based on posture or size:

val config = mediaQuery {
    when (windowPosture) {
        UiMediaScope.Posture.Tabletop -> tabletopGridConfig
        else -> defaultGridConfig
    }
}

Grid(config = { /* use config */ }) {
    // Place items with gridItem
}

See the official adaptive apps guides for full Grid + mediaQuery recipes, including tabletop video players.

Preview adaptive states

Override LocalUiMediaScope in previews to test specific postures or sizes:

@Preview
@Composable
fun PreviewTabletop() {
    ComposeUiFlags.isMediaQueryIntegrationEnabled = true
    val customScope = object : UiMediaScope by LocalUiMediaScope.current {
        override val windowPosture = UiMediaScope.Posture.Tabletop
    }
    CompositionLocalProvider(LocalUiMediaScope provides customScope) {
        VideoPlayer()
    }
}

This lets you verify tabletop and book layouts without physical hardware.

Tips for production use

  • Prefer derivedMediaQuery for windowWidth and windowHeight to reduce recomposition cost.
  • Keep queries simple; complex logic inside the lambda can affect performance.
  • Test on foldables using Android Studio’s posture emulators or Device Streaming.
  • Combine with Navigation 3 and adaptive list-detail patterns for full-screen experiences.
  • Monitor the experimental status; the API is available in recent Compose versions and expected to stabilize.

Conclusion

mediaQuery removes brittle device-type checks and lets your Compose UI react to the actual window environment. Enable the flag, query posture and size, and build layouts that work across phones, foldables, tablets, and larger Android devices. Official documentation and the Android Developers sessions provide further examples.

Sources

Share this story

Filed under: androidtutorialshow-to