Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

120 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

AppDimens Dynamic

Responsive dp / sp for Android — Jetpack Compose and Kotlin APIs

Version 3.1.7   License Apache 2.0   Platform Android   Kotlin   Jetpack Compose   Min SDK 24   14 scaling modes

Beginner guide    Full documentation    API documentation    KDoc reference

Performance report    Performance comparative    R8 and ProGuard rules


AppDimens Banner

Write values like 16.sdp and the library scales them from the current screen Configuration (size, density, optional flags).

New here? Use Quick start below, then GUIDE-FOR-BEGINNERS for every strategy in plain language.

Documentation: DOCUMENTATION/README.md · DOCUMENTATION/MODULES.md · KDoc (hosted) · PRD · PDR · Mathematics


Installation (v3.1.7)

3.1.7 keeps the modular packaging introduced in 3.1.6: the library ships as a principal artifact (common + core + scaled + plain) plus optional strategy modules. Kotlin packages and imports are unchanged.

With BOM

dependencies {
    implementation(platform("io.github.bodenberg:appdimens-dynamic-bom:3.1.7"))

    implementation("io.github.bodenberg:appdimens-dynamic")

    implementation("io.github.bodenberg:appdimens-dynamic-percent")
    implementation("io.github.bodenberg:appdimens-dynamic-power")
    implementation("io.github.bodenberg:appdimens-dynamic-fluid")
    implementation("io.github.bodenberg:appdimens-dynamic-auto")
    implementation("io.github.bodenberg:appdimens-dynamic-density")
    implementation("io.github.bodenberg:appdimens-dynamic-diagonal")
    implementation("io.github.bodenberg:appdimens-dynamic-fill")
    implementation("io.github.bodenberg:appdimens-dynamic-fit")
    implementation("io.github.bodenberg:appdimens-dynamic-interpolated")
    implementation("io.github.bodenberg:appdimens-dynamic-logarithmic")
    implementation("io.github.bodenberg:appdimens-dynamic-perimeter")
    implementation("io.github.bodenberg:appdimens-dynamic-resize")
    implementation("io.github.bodenberg:appdimens-dynamic-units")
}

Missing strategy module

If you import com.appdimens.dynamic.compose.<strategy> (or code.<strategy>) without adding the matching artifact, the Gradle check checkAppDimensModules fails with a line such as:

Missing AppDimens module for import …percent… — add: implementation("io.github.bodenberg:appdimens-dynamic-percent:3.1.7")

Apply the same check in your app with:

apply(from = "<path-to-checkout>/gradle/appdimens-missing-module-check.gradle.kts")

Runtime helper: com.appdimens.dynamic.core.MissingModule (package → Maven coordinate). Version comes from the appdimens.version Gradle property.

Without BOM

dependencies {
    implementation("io.github.bodenberg:appdimens-dynamic:3.1.7")
    implementation("io.github.bodenberg:appdimens-dynamic-percent:3.1.7")
    // same satellites as above, each with :3.1.7
}

Migration from 3.1.5 (modularization baseline)

3.1.5 3.1.6
One appdimens-dynamic dependency with every strategy Principal = scaled + core; declare each extra strategy module
Optional appdimens-dynamic-bom for shared version management
Kotlin imports Unchanged

Migration from 3.1.6 to 3.1.7

No API, import, or packaging changes — 3.1.7 is an internal correctness and performance release; upgrade by bumping the version. Highlights of what changed under the hood:

  • Persistent result cache removed. DimenCache no longer writes to Preferences DataStore. The in-memory cache is partitioned per window/configuration snapshot (DimenMetrics), so a rotated, resized, or recreated window can never observe values computed for another size, density, font scale, or multi-window state.
  • Exact aspect-ratio math. The hand-maintained binary-search lookup table in AspectRatioLookup was replaced by a deterministic ln() computed once per snapshot — nearby screen ratios no longer collapse to the same approximated value.
  • Atomic cache entries. Key and value are published as a single immutable reference, eliminating the key/value race that could return another key’s value under concurrency.
  • Per-window correctness for Compose. AppDimensProvider provides LocalDimenMetrics; the rememberDimen* helpers keep every dimension in a composition on the same coherent snapshot and remember on two keys instead of four.
  • Memory-leak fix. The Context → Activity weak cache was removed.
  • Build/toolchain refresh: Kotlin 2.4.10, AGP 9.2.1, Compose BOM 2026.06.01, Material 1.14.0; CI uses least-privilege permissions and updated Actions; the Dokka output path is portable and git-ignored.

Artifact matrix

Maven artifact Contents
appdimens-dynamic common, core, code.plain, code / compose scaled
appdimens-dynamic-<strategy> code.<strategy> + compose.<strategy>
appdimens-dynamic-bom Version constraints (java-platform)

Module graph: DOCUMENTATION/MODULES.md.

Requirements: Min SDK 24 · Compile SDK 36 · Kotlin & Java 17 · Jetpack Compose


Quick start — Scaled (Compose)

import com.appdimens.dynamic.compose.*

Box(
    Modifier
        .padding(16.sdp)
        .width(100.wdp)
        .height(48.hdp)
) {
    Text("Hello", fontSize = 16.ssp)
}
Extension Based on Typical use
sdp Smallest window width Padding, margins
hdp Screen height Row height
wdp Screen width Column width
ssp Same idea as sdp, for text fontSize
sem Same idea as sdp, for text fontSize ignore system font scale

Compose — setup before advanced APIs

If you only use sdp / hdp / wdp / ssp / hsp / wsp/ sem / hem / wem (and variants like sdpa), you can skip this block.

AppDimensProvider

Use it when you call .sdpMode, .sdpScreen, .sspMode, .sspScreen, or similar facilitators that depend on UI mode / fold state. It sets LocalUiModeType once for the tree instead of resolving mode on every call, and (since 3.1.7) provides LocalDimenMetrics — a coherent per-window snapshot that every rememberDimen* helper uses.

import com.appdimens.dynamic.core.AppDimensProvider

setContent {
    AppDimensProvider {
        MyApp()
    }
}

DimenCache.invalidateOnConfigChange

Since 3.1.7 the cache is partitioned per window snapshot (DimenMetrics): every resolution is keyed by the exact configuration it was computed for, so a rotated, resized, or recreated window can never read a stale value. Explicit invalidation is therefore not required for correctness — this API is retained as a compatibility hook and no longer wipes other windows’ hot entries.

Call it when the same Activity stays alive across rotation, split-screen, or density/font changes and you want to refresh internal bookkeeping. If the Activity is recreated on config change (default), you don’t need it. Details: library/PERFORMANCE.md.

The previous Configuration is tracked internally by DimenCache — callers only need to pass the new one.

import com.appdimens.dynamic.core.DimenCache

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    DimenCache.invalidateOnConfigChange(newConfig)
}

You only get onConfigurationChanged if the Activity lists android:configChanges for those changes in the manifest; otherwise the process usually recreates the Activity and config is fresh automatically.


Compose — next steps

Suffixes (a, i, ia)

Suffix Meaning
(none) Default
a Aspect ratio–aware curve
i Ignore multi-window heuristic (may return unscaled base when it triggers)
ia Both
16.sdpa      // + aspect ratio
32.hdpi      // height axis + ignore multi-window
16.sspa      // scalable sp + aspect ratio

More text styles

Text("Scaled (sw)", fontSize = 16.ssp)
Text("Scaled (height)", fontSize = 20.hsp)
Text("Scaled (width)", fontSize = 18.wsp)
Text("No system font scale (sw)", fontSize = 16.sem)   // sem / hem / wem

Orientation inverters (examples)

32.sdpPh   // SW-based; in portrait uses height
32.sdpLw   // SW-based; in landscape uses width
50.hdpLw   // Height-based; in landscape uses width
50.wdpLh   // Width-based; in landscape uses height

Facilitators (after AppDimensProvider if you use mode/screen)

import com.appdimens.dynamic.compose.*
import com.appdimens.dynamic.common.DpQualifier
import com.appdimens.dynamic.common.Orientation
import com.appdimens.dynamic.common.UiModeType

80.sdpRotate(50, orientation = Orientation.LANDSCAPE)
30.sdpMode(200, UiModeType.TELEVISION)
60.sdpQualifier(120, DpQualifier.SMALL_WIDTH, 600)
16.sspRotate(24, orientation = Orientation.LANDSCAPE)

Full catalog: DOCUMENTATION/COMPOSE-API-CONVENTIONS.md.

Builders (scaledDp / scaledSp)

val pad = 16.scaledDp()
    .aspectRatio(true)
    .screen(UiModeType.TELEVISION, 40)
    .screen(DpQualifier.SMALL_WIDTH, 600, 24)
    .sdp

Auto-resize (inside BoxWithConstraints)

Picks the largest font or size in a min…max range that still fits the space. Use for titles, squares, etc.

import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.ui.Modifier
import com.appdimens.dynamic.compose.resize.autoResizeTextSp

BoxWithConstraints(Modifier.fillMaxWidth()) {
    val fontSize = autoResizeTextSp(
        text = "Headline that must fit",
        minSp = 12,
        maxSp = 28,
        stepSp = 1,
        maxLines = 2,
    )
    Text("Headline that must fit", fontSize = fontSize, maxLines = 2)
}

More APIs (autoResizeSquareSize, ResizeBound, …): DOCUMENTATION/resize.md.


Kotlin (Views / non-Composable)

import com.appdimens.dynamic.code.DimenSdp
import com.appdimens.dynamic.code.DimenSsp

val paddingPx = DimenSdp.sdp(context, 16)
val heightPx = DimenSdp.hdp(context, 32)
val widthPx = DimenSdp.wdp(context, 100)
val fontPx = DimenSsp.ssp(context, 16)

// Extensions (see code package)
// 16.ssp(context), DimenSdp.scaled(16).screen(...).sdp(context), sdpRotate, …

Java

import com.appdimens.dynamic.code.DimenSdp;
import com.appdimens.dynamic.code.DimenScaled;
import com.appdimens.dynamic.code.DimenSsp;
import com.appdimens.dynamic.common.UiModeType;

float paddingPx = DimenSdp.sdp(context, 16);
float heightPx = DimenSdp.hdp(context, 32);
float fontPx = DimenSsp.ssp(context, 16);

DimenScaled scaled = DimenSdp.scaled(16)
    .applyAspectRatio(true)
    .screen(UiModeType.TELEVISION, 32);
float result = scaled.sdp(context);

Physical units (mm, cm, inch)

Approximate real-world size on screen (density-based). Compose: use helpers from the library and .dp on the result where needed — see DOCUMENTATION/physical-units.md. Code module: com.appdimens.dynamic.code.units.DimenPhysicalUnits (toDpFromMm, …).


Layout example   Benchmark


More strategies & full API

Recommendation order for most apps: Scaled (with or without a) → then percent → then auto; explore the rest when you have a clear need (fluid, fit, diagonal, etc.).

Other strategies (percent, power, fluid, auto, diagonal, fill, fit, interpolated, logarithmic, perimeter, density, resize, units) mirror the Scaled suffix patterns under a different import prefix and ship as separate Maven modules. See DOCUMENTATION/MODULES.md, DOCUMENTATION/README.md, and GUIDE-FOR-BEGINNERS.

Resource Use for
DOCUMENTATION/README.md Per-strategy explanations
DOCUMENTATION/MODULES.md Gradle/Maven module graph (3.1.7)
COMPOSE-API-CONVENTIONS.md Every Compose property & facilitator (scaled catalog + prefix map)
DOCUMENTATION/index.md Markdown API index (KDoc export)
appdimens3.web.app Searchable KDoc

Example app: app/.../compose/ExampleActivity.kt (includes auto-resize demos).


Optional: cache & performance

  • Results are cached in DimenCache — lock-free, partitioned per window/configuration snapshot (no disk persistence since 3.1.7).
  • Some paths skip storing in the shard table when a cheap multiply is enough — see library/PERFORMANCE.md.
  • Batch / low-level keys: not needed for normal app code; library extensions already use the cache.

Scaled uses 300 dp as the design reference. It is the most widely used strategy in real apps and the recommended default: use plain sdp / hdp / wdp / ssp when a single curve is enough, and the a suffix (aspect ratio–aware), e.g. 16.sdpa, when you want scaling tuned to screen shape. After Scaled, the next strategies teams typically adopt are percent (sizes as a fraction of an axis) and auto (breakpoint-style steps); the other modes are for specialized layouts — see DOCUMENTATION/README.md.


Facilitators — two “Plain” styles: *RotatePlain, *ModePlain, *QualifierPlain, *ScreenPlain (and *PlainPx) exist with the alternate as Number (active branch still runs through scaling/cache) or as Dp / TextUnit (only the condition is evaluated; no second scaling). For nested chains such as 30.sdp.sdpRotatePlain(20.sdp).sdpModePlain(40.sdp, UiModeType.TELEVISION), prefer Dp / TextUnit alternates so neither the receiver nor the alternate is scaled twice. Nesting order is the order you write the chain (outer → inner). That is different from DimenScaled .screen chains, where priority is defined inside the builder API, not by lexical nesting — see DOCUMENTATION/COMPOSE-API-CONVENTIONS.md.


Views / code: the same logic-only Plain branching exists on Float px + ContextDimen*PlainPx.kt per strategy (e.g. psdpRotatePlainPx in com.appdimens.dynamic.code.percent), with shared helpers in com.appdimens.dynamic.code.plain (DimenPlainBranch.kt). Dp/Sp facilitator sources use the same Dimen<Strategy>DpExtensions.kt / Dimen<Strategy>SpExtensions.kt names as in compose/<strategy>/ (scaled: DimenSdpExtensions.kt / DimenSspExtensions.kt under code/scaled/). Details in DOCUMENTATION/COMPOSE-API-CONVENTIONS.md §4.5 and DOCUMENTATION/README.md.


Highlights (v3.x)

  • Code-only scaling (no XML dimen grids) · SDP / HDP / WDP + 14 scaling modes
  • Aspect ratio & multi-window flags · Inverters & facilitators · Foldable awareness via WindowManager
  • Physical units · Resize helpers · DimenScaled chains
  • 3.1.7: per-window DimenMetrics snapshots · atomic snapshot-partitioned cache · exact ln aspect-ratio math · persistence removed · multi-window / Compose correctness and leak fixes

Apache License 2.0 — responsive layout utilities for Android.

About

The most complete responsive dimension library standard by also introducing height-to-width and width-to-width scaling. (sdp, hdpi, wdp, dimens, dimension, dimensions, dp, sp, dimen, responsive, adaptative, text unit, font scale, font size, resize, textunit, mm, cm, inch, device, physical, android, dpi, sdpi, auto, hdpi, ldpi, mdpi, precision)

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages