Bodenberg.AppDimens.Dynamic

May 17, 2026 · View on GitHub

.NET 10 binding for Android (net10.0-android) that wraps AppDimens Dynamic — responsive dp / sp / px sizing in code (no XML dimen grids), with 15 scaling strategies, conditional facilitators, aspect-ratio and multi-window variants, physical units, auto-resize helpers, and optional DataStore-backed caching.

Kotlin/Java sources, strategy semantics, and Android-focused guides live upstream:

bodenberg/appdimens-dynamic · DOCUMENTATION · KDoc search

Maven artifact embedded in this package: io.github.bodenberg:appdimens-dynamic 3.1.5.


Install

dotnet add package Bodenberg.AppDimens.Dynamic --version 3.5.1.4

Requirements

RequirementNotes
Target frameworknet10.0-android (.NET for Android / .NET MAUI Android)
Minimum Android API24 (matches the packaged AAR)
WorkloadAndroid (dotnet workload install android) or MAUI
JDK17 or 21 for the Xamarin.Android toolchain on .NET 10

Use Android SDK platform 36+ (or MSBuild InstallAndroidDependencies) when building bindings locally on .NET 10.


What this library provides

CapabilitySummary
Scaled (default)SDP / HDP / WDP and SSP / HSP / WSP — design reference 300 dp; recommended starting point
14 extra strategiespercent, auto, power, fluid, diagonal, fill, fit, interpolated, logarithmic, perimeter, density — same suffix patterns, different math
Suffixesa (aspect ratio), i / ia (multi-window ignore paths), combined with axis helpers
InvertersPh, Lh, Pw, Lw — switch width/height/smallest-width basis by orientation (e.g. SdpPh, HspLw)
FacilitatorsRotate, Mode, Qualifier, Screen — conditional overrides (orientation, UI mode, sw/w/h buckets, foldables)
BuildersDimenScaled / per-strategy *Scaled — priority-ordered rule lists (unlike nested facilitator order)
Physical unitsmm / cm / inch → dp/sp/px via DimenPhysicalUnits
ResizeDimenResize — auto-resize text/layout helpers (see upstream DOCUMENTATION/resize.md)
CacheDimenCache — lock-free shards, optional persistence (DataStore); call InvalidateOnConfigChange on configuration changes

C# namespaces (binding layout)

Public Kotlin @JvmStatic APIs appear under Com.Appdimens.Dynamic.* (Java package → C# namespace):

AreaNamespace (examples)
Views / imperative (recommended)Com.Appdimens.Dynamic.Code
Scaled helpersCom.Appdimens.Dynamic.CodeDimenSdp, DimenSsp, DimenScaled
Other strategiesCom.Appdimens.Dynamic.Code.Percent, .Auto, .Power, .Fluid, .Diagonal, .Fill, .Fit, .Interpolated, .Logarithmic, .Perimeter, .Density
Plain px branchingCom.Appdimens.Dynamic.Code.Plain, *.Dimen*PlainPxKt per strategy
Physical unitsCom.Appdimens.Dynamic.Code.UnitsDimenPhysicalUnits
ResizeCom.Appdimens.Dynamic.Code.Resize
Shared enumsCom.Appdimens.Dynamic.CommonDpQualifier, Inverter, Orientation, UiModeType, UnitType
Cache / providerCom.Appdimens.Dynamic.CoreDimenCache, AppDimensProvider, …
Compose (limited)Com.Appdimens.Dynamic.Compose.* — see Jetpack Compose below

Foldable-aware overloads use AndroidX.Window.Layout.IFoldingFeature from Xamarin.AndroidX.Window.


Quick start (Activity / Views)

Warm the cache once (recommended), then read pixel sizes:

using Android.App;
using Android.OS;
using Com.Appdimens.Dynamic.Code;

[Activity(Label = "My App", MainLauncher = true)]
public class MainActivity : Activity
{
    protected override void OnCreate(Bundle? savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        DimenSdp.WarmupCache(this);

        float paddingPx = DimenSdp.Sdp(this, 16);
        float heightPx  = DimenSdp.Hdp(this, 32);
        float widthPx   = DimenSdp.Wdp(this, 100);
        float fontPx    = DimenSsp.Ssp(this, 16);
    }

    public override void OnConfigurationChanged(Android.Content.Res.Configuration newConfig)
    {
        base.OnConfigurationChanged(newConfig);
        Com.Appdimens.Dynamic.Core.DimenCache.InvalidateOnConfigChange(newConfig);
    }
}

Scaled API (DimenSdp / DimenSsp)

Primary entry points in Com.Appdimens.Dynamic.Code:

FamilyMethods (pattern)Axis
SDPSdp, Sdpa, Sdpi, Sdpia, …Smallest width
HDPHdp, Hdpa, Hdpi, …Height
WDPWdp, Wdpa, Wdpi, …Width
SSPSsp, Sspa, Sspi, …Text (smallest width)
HSP / WSPHsp, Wsp, + a / i / ia variantsText by height / width

Inverter shortcuts (orientation-aware axis switch), examples:

  • SdpPh / SdpPha — smallest width in portrait → height in landscape
  • SdpLw / SdpLwa — smallest width → width in landscape
  • HdpLw, WspLh, … — same idea for HDP / WSP

Facilitators (imperative), examples:

// Landscape uses 24 sdp, otherwise 16
float pad = DimenSdp.SdpRotate(this, 16, 24);

// TV UI mode override
float tvTitle = DimenSsp.SspMode(this, 16, 22, Com.Appdimens.Dynamic.Common.UiModeType.Television);

// sw ≥ 600 bucket
float tablet = DimenSdp.SdpQualifier(this, 16, 20,
    Com.Appdimens.Dynamic.Common.DpQualifier.SmallWidth, 600);

// Combined UI mode + qualifier (+ optional FoldingFeature overloads)
float fold = DimenSdp.SdpScreen(this, 16, 28,
    Com.Appdimens.Dynamic.Common.UiModeType.Television,
    Com.Appdimens.Dynamic.Common.DpQualifier.SmallWidth, 600);

Kotlin extension-style facilitators (sdpRotatePlain, nested chains) are exposed as DimenSdpExtensionsKt / DimenSspExtensionsKt when generated; prefer plain Dp/float overloads in C# when chaining to avoid double scaling (see upstream COMPOSE-API-CONVENTIONS).


DimenScaled builder

Build a rule list; resolution uses priority inside the builder, not lexical nesting:

using Com.Appdimens.Dynamic.Code;
using Com.Appdimens.Dynamic.Common;

var scaled = DimenSdp.Scaled(16)
    .Screen(UiModeType.Television, DpQualifier.SmallWidth, 600, 40f)
    .Screen(UiModeType.Television, 32f)
    .Screen(Orientation.Landscape, 20f);

float px = scaled.Sdp(this);

Use DimenSsp.Scaled / ScaledSp for typography with the same .Screen(...) pattern.


Other scaling strategies

Each strategy lives under Com.Appdimens.Dynamic.Code.<Strategy> with Dimen<Strategy>, Dimen<Strategy>Dp, Dimen<Strategy>Sp, extension/facilitator types, and optional *Scaled builders.

StrategyTypical use
percentSize as fraction of width/height/smallest width
autoBreakpoint-style steps (similar to responsive CSS)
powerPower-curve scaling
fluidFluid interpolation between bounds
diagonalScreen diagonal based
fill / fitFill or fit a proportion of the canvas
interpolatedInterpolated curves between anchors
logarithmicLog-shaped response
perimeterPerimeter-based scaling
densityDensity-aware adjustments

Recommendation: start with Scaled → then percent / auto when needed; adopt others for specialized layouts (strategy guide).

Method prefixes mirror Scaled (psdp, asdp, fsdp, …) — import the matching Dimen* type for that strategy.


Physical units

Com.Appdimens.Dynamic.Code.Units.DimenPhysicalUnits converts real-world units using display metrics:

using Com.Appdimens.Dynamic.Code.Units;

float dpFromMm = DimenPhysicalUnits.ToDpFromMm(10f, Resources);
float pxFromCm = DimenPhysicalUnits.ToPxFromCm(2f, Resources);
float spFromInch = DimenPhysicalUnits.ToSpFromInch(0.25f, Resources);

Also: MmToCm, RadiusFromDiameter, RadiusFromCircumference, etc.


Resize helpers

Com.Appdimens.Dynamic.Code.Resize.DimenResize / DimenResizeKt expose auto-resize utilities (text size, square size, bounds). Compose-oriented variants may reference Composer; for .NET, check generated members or follow upstream DOCUMENTATION/resize.md.


Cache and configuration

Com.Appdimens.Dynamic.Core.DimenCache:

APIWhen to use
WarmupCache / InitApp start (also invoked via DimenSdp.WarmupCache)
InvalidateOnConfigChange(Configuration)onConfigurationChanged / after locale, density, or size class changes
Clear / ClearAllDebug or user “reset layout” flows
Stats / diagnosticsPerformance tuning

Persistence uses AndroidX DataStore; this NuGet pulls Xamarin.AndroidX.DataStore.Preferences (required at runtime for DimenCache).


Jetpack Compose (com.appdimens.dynamic.compose)

The AAR ships Compose extensions (DimenSdpKt, DimenAutoKt, autoResizeTextSp, …) that take androidx.compose.runtime.Composer. With the current class-parse binding pipeline, many Compose helpers are not practical from C# (missing or incomplete Composer wrappers).

Use this package for:

  • Com.Appdimens.Dynamic.Code — Activities, Fragments, custom View measurement, MAUI Android handlers
  • Com.Appdimens.Dynamic.Core / Common — cache, qualifiers, shared types

Compose-first apps on .NET may need a future binding strategy or shared logic called from Kotlin.


Dependencies brought in by this package

NuGetRole
Xamarin.Kotlin.StdLibKotlin runtime for bound types
Xamarin.AndroidX.CoreCore / Context extensions
Xamarin.AndroidX.WindowFoldables (FoldingFeature)
Xamarin.AndroidX.Lifecycle.RuntimeLifecycle alignment with upstream AAR
Xamarin.AndroidX.DataStore.PreferencesDimenCache persistence (1.2.1, aligned with Maven datastore-preferences)

Package version vs embedded AAR

LayerVersion
Maven / embedded .aarappdimens-dynamic 3.1.5
NuGet3.5.1.4net10.0-android and updated Xamarin AndroidX/DataStore; Android binary still 3.1.5

When Maven publishes 3.5.1, run ./scripts/sync-aar-from-maven.sh 3.5.1 and align the fourth NuGet segment as needed.


Build this binding locally

cd appdimens-dynamic-net-binding
dotnet build AppDimens.Dynamic.sln -c Release

Optional smoke APK: AppDimens.Dynamic.SmokeTest. See NUGET-PUBLISH.md.

Sync the upstream AAR:

./scripts/sync-aar-from-maven.sh 3.1.5

ResourceURL
AppDimens (main project — NuGet Project website)https://github.com/bodenberg/appdimens
Android library (NuGet Source repository; implementation & issues)https://github.com/bodenberg/appdimens-dynamic
Strategy documentationhttps://github.com/bodenberg/appdimens-dynamic/tree/main/DOCUMENTATION
Maven Centralhttps://repo1.maven.org/maven2/io/github/bodenberg/appdimens-dynamic/3.1.5/
.NET binding monorepohttps://github.com/bodenberg/appdimens-net-binding

License

Apache 2.0, consistent with the upstream library.