Languages: English | Português (BR) | Español
Comprehensive Technical Documentation - Everything You Need to Know
Author: Jean Bodenberg
Date: February 2025
Version: 2.0.0
🆕 Version 2.0: Expanded from 2 to 13 scaling strategies, including perceptual models (BALANCED⭐, LOGARITHMIC, POWER), Smart Inference, and 5x performance improvements.
The most comprehensive responsive sizing library, combining mathematical rigor with practical simplicity.
📚 This is the DEFINITIVE document. Everything about AppDimens 2.0 is here. For quick starts, see Simplified Guide.
- PRIMARY: BALANCED Strategy
- SECONDARY: DEFAULT Strategy
- Perceptual Models: LOGARITHMIC & POWER
- Utility Strategies: FLUID, INTERPOLATED, etc
- Game Strategies: FIT & FILL
- Special: AUTOSIZE & NONE
- Android Complete Guide
- iOS Complete Guide
- Flutter Complete Guide
- React Native Complete Guide
- Web Complete Guide
- Smart Inference System
- Base Orientation Support
- Physical Units
- Game Development Modules
- Cache and Performance
Modern apps must work across:
- 📱 Phones (320-480dp)
- 📱 Phablets (480-600dp)
- 📱 Small Tablets (600-720dp)
- 📺 Large Tablets (720-840dp)
- 📺 TVs (960-1920dp+)
- ⌚ Watches (< 300dp)
- 💻 Web (320-3840px+)
Problem: A fixed 48dp button:
- Looks good on phones (13% of screen)
- Looks tiny on tablets (6.7% of screen)
- Looks microscopic on TVs (2.5% of screen)
Linear scaling (SDP): Opposite problem:
- Looks good on phones (48dp)
- Looks too big on tablets (96dp)
- Looks enormous on TVs (144dp)
An ideal solution must:
- ✅ Adapt to screen size
- ✅ Control excessive growth
- ✅ Consider aspect ratio
- ✅ Maintain visual consistency
- ✅ Perform efficiently
- ✅ Work across all platforms
Version 2.0 introduces:
-
13 Scaling Strategies (vs 2 in v1.x)
- Perceptual: BALANCED ⭐, LOGARITHMIC, POWER
- Legacy: DEFAULT, PERCENTAGE
- Utility: FLUID, INTERPOLATED, DIAGONAL, PERIMETER
- Game: FIT, FILL
- Special: AUTOSIZE 🆕, NONE
-
Primary Recommendation: BALANCED ⭐
- Hybrid linear-logarithmic
- Linear on phones (< 480dp)
- Logarithmic on tablets/TVs (≥ 480dp)
- 40% oversizing reduction
-
Smart Inference System 🧠
- Automatic strategy selection
- 18 element types
- 8 device categories
- Weight-based algorithm
-
5x Performance Improvement ⚡
- Lock-free cache (0.001µs)
- Ln() lookup table (10-20x faster)
- Pre-calculated constants
- Binary search O(log n)
| Approach | Phone (360dp) | Tablet (720dp) | Problem |
|---|---|---|---|
| Traditional DP | 48dp (13%) | 48dp (6.7%) ❌ | Too small on tablets |
| Linear (SDP) | 58dp (16%) | 115dp (16%) ❌ | Too big on tablets |
| AppDimens BALANCED ⭐ | 58dp (16%) ✅ | 70dp (10%) ✅ | Perfect! |
New Features:
- ✅ 11 new scaling strategies
- ✅ BALANCED as primary recommendation
- ✅ Smart Inference with auto-selection
- ✅ 5x performance improvements
- ✅ Enhanced TypeScript/JavaScript support
Renamed (Clarity):
Fixed→DEFAULT(phone-focused, secondary recommendation)Dynamic→PERCENTAGE(proportional, specific use)
Backward Compatibility:
- ✅ Old extensions still work (
.fxdp,.dydp) - ✅ Deprecated warnings guide migration
- ✅ Zero breaking changes
Old code (v1.x) - Still works:
Text("Hello", fontSize = 16.fxsp) // Deprecated but functionalNew code (v2.0) - Recommended:
// Primary recommendation
Text("Hello", fontSize = 16.balanced().sp) // ⭐ BALANCED
// Secondary (equivalent to old Fixed)
Text("Hello", fontSize = 16.defaultDp.sp) // DEFAULT
// Large containers (equivalent to old Dynamic)
Container(modifier = Modifier.width(300.percentageDp.dp))🏆 Primary Recommendation: Use for 95% of applications, especially multi-device apps.
f_BALANCED(x, W) = {
x × (W / 300) if W < 480dp
x × (1.6 + 0.40 × ln(1 + (W-480)/300)) if W ≥ 480dp
}
Components:
- Linear region: W < 480dp (phones)
- Logarithmic region: W ≥ 480dp (tablets/TVs)
- Transition point: 480dp
- Sensitivity: k = 0.40
| Screen | BALANCED | LINEAR | Reduction |
|---|---|---|---|
| 240dp | 38.4dp | 38.4dp | 0% |
| 300dp | 48.0dp | 48.0dp | Reference |
| 360dp | 57.6dp | 57.6dp | 0% (linear) |
| 480dp | 76.8dp | 76.8dp | 0% (transition) |
| 600dp | 85.0dp | 96.0dp | -11.5% |
| 720dp | 69.7dp | 115.2dp | -39.5% ⭐ |
| 960dp | 88.3dp | 153.6dp | -42.5% |
| 1080dp | 100.9dp | 172.8dp | -41.6% |
Android:
// Extension
16.balanced().dp
16.balanced().sp
// Builder
AppDimens.balanced(16).toDp(resources)
AppDimens.balanced(16).toSp(resources)iOS:
AppDimens.shared.balanced(16).toPoints()
AppDimens.shared.balanced(16).toPt()Flutter:
AppDimens.balanced(16).calculate(context)
16.0.balanced()React Native:
const {balanced} = useAppDimens();
balanced(16)Web:
const {balanced} = useWebDimens();
balanced(16)✅ Ideal For:
- Multi-device apps (phones + tablets + TVs)
- Social media, productivity, e-commerce
- Buttons, spacing, padding
- General UI elements
- 95% of modern applications
❌ Consider Alternatives:
- Phone-only apps → Use DEFAULT
- Large containers → Use PERCENTAGE
- Maximum control → Use LOGARITHMIC
📖 Complete BALANCED Documentation
Secondary Recommendation: Use for phone-focused apps and backward compatibility.
f_DEFAULT(x, W, AR) = x × [1 + ((W-300)/1) × (0.00333 + 0.00267×ln(AR/1.78))]
Components:
- ~97% linear:
((W-300) × 0.00333) - ~3% AR adjustment:
((W-300) × 0.00267×ln(AR/1.78))
| Screen | DEFAULT | BALANCED | LINEAR |
|---|---|---|---|
| 360dp | 53.8dp | 57.6dp | 57.6dp |
| 480dp | 64.5dp | 76.8dp | 76.8dp |
| 720dp | 79.2dp | 69.7dp | 115.2dp |
| 1080dp | 94.0dp | 100.9dp | 172.8dp |
Android:
16.defaultDp // Extension
16.defaultSp
AppDimens.defaultScaling(16).toDp(resources)iOS:
AppDimens.shared.defaultScaling(16).toPoints()Flutter:
AppDimens.defaultScaling(16).calculate(context)✅ Ideal For:
- Phone-focused apps (320-480dp)
- Icons and small elements
- Apps with elongated screens (20:9, 21:9)
- Backward compatibility with v1.x
📖 Complete DEFAULT Documentation
Formula:
f_LOG(x, W) = x × (1 + 0.40 × ln(W/300))
Results: 48dp @ 720dp = 67.2dp (-42% vs linear)
Use for: TV apps, maximum control
Score: 88/100 🥈
Formula:
f_POWER(x, W) = x × (W/300)^0.75
Results: 48dp @ 720dp = 76.8dp (-33% vs linear)
Use for: General purpose, configurable
Score: 86/100 🥉
| Strategy | Formula | Use Case | Score |
|---|---|---|---|
| PERCENTAGE | x × (W/300) |
Large containers | 62/100 |
| FLUID | clamp(min, interp, max) |
Typography | 78/100 |
| INTERPOLATED | x × (0.5 + 0.5×W/300) |
Moderate | 70/100 |
| DIAGONAL | x × √(W²+H²)/611.63 |
Physical size | 72/100 |
| PERIMETER | x × (W+H)/833 |
W+H balance | 70/100 |
FIT (Letterbox): x × min(W/300, H/533)
FILL (Cover): x × max(W/300, H/533)
Scores: 75/100, 73/100
AUTOSIZE 🆕: Container-aware auto-sizing (O(log n) binary search)
NONE: No scaling (identity function)
dependencies {
// Core library (13 strategies + Physical Units)
implementation("io.github.bodenberg:appdimens-dynamic:2.0.1")
// SDP/SSP (XML support)
implementation("io.github.bodenberg:appdimens-sdps:2.0.1")
implementation("io.github.bodenberg:appdimens-ssps:2.0.1")
// All-in-one
implementation("io.github.bodenberg:appdimens-all:2.0.1")
// Games (C++/NDK)
implementation("io.github.bodenberg:appdimens-games:2.0.1")
}// BALANCED (Primary) ⭐
Text("Hello", fontSize = 16.balanced().sp)
Box(modifier = Modifier.size(48.balanced().dp))
// DEFAULT (Secondary)
Icon(modifier = Modifier.size(24.defaultDp))
// PERCENTAGE (Containers)
Container(modifier = Modifier.width(300.percentageDp.dp))
// Smart API
Button(modifier = Modifier.height(
48.smart().forElement(ElementType.BUTTON).dp
))
// FLUID (Typography)
Text("Title", fontSize = fluidSp(16f, 24f))
// All other strategies
Text("Powerful", fontSize = 16.power(0.75f).sp)
Text("Logarithmic", fontSize = 16.logarithmic().sp)val width = 300.balanced().toPx(resources)
val height = 48.defaultScaling().toPx(resources)
view.layoutParams.width = width.toInt()<TextView
android:textSize="@dimen/_16ssp"
android:padding="@dimen/_12sdp"
android:layout_width="@dimen/_300sdp" />CocoaPods:
pod 'AppDimens', '~> 2.0.0'SPM:
.package(url: "https://github.com/bodenberg/appdimens.git", from: "2.0.0")// BALANCED (Primary) ⭐
Text("Hello")
.font(.system(size: AppDimens.shared.balanced(16).toPoints()))
// DEFAULT (Secondary)
Image(systemName: "heart")
.frame(width: AppDimens.shared.defaultScaling(24).toPoints())
// Smart API
Button("Click") {}
.frame(height: AppDimens.shared.smart(48).forElement(.button).toPoints())
// FLUID
Text("Title")
.font(.system(size: AppDimens.shared.fluid(min: 16, max: 24).toPoints()))let size = AppDimens.shared.balanced(48).toPoints()
button.frame = CGRect(x: 0, y: 0, width: size, height: size)dependencies:
appdimens: ^2.0.0// BALANCED (Primary) ⭐
Text(
'Hello',
style: TextStyle(fontSize: AppDimens.balanced(16).calculate(context)),
)
// Extensions
Container(
width: 300.balanced(),
height: 200.defaultScaling(),
)
// Smart API
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: Size(
double.infinity,
AppDimens.smart(48).forElement(ElementType.button).calculate(context),
),
),
)
// FLUID
Text(
'Title',
style: TextStyle(
fontSize: AppDimens.fluid(16, maxValue: 24).calculate(context),
),
)npm install [email protected]{% raw %}
import {useAppDimens} from 'appdimens-react-native';
function MyComponent() {
const {balanced, defaultScaling, smart} = useAppDimens();
return (
<View style={{padding: balanced(16)}}>
<Text style={{fontSize: balanced(18)}}>Hello</Text>
<TouchableOpacity style={{height: smart(48).forElement('button')}}>
<Text>Click</Text>
</TouchableOpacity>
</View>
);
}{% endraw %}
npm install [email protected]{% raw %}
import {useWebDimens} from 'webdimens/react';
function MyComponent() {
const {balanced, fluid, smart} = useWebDimens();
return (
<div style={{padding: balanced(16)}}>
<h2 style={{fontSize: fluid(18, 24)}}>Title</h2>
<button style={{height: smart(48).forElement('button')}}>
Click
</button>
</div>
);
}{% endraw %}
See platform-specific hooks and services.
// Automatically selects best strategy based on element type
val buttonSize = 48.smart().forElement(ElementType.BUTTON).dp
// → Selects BALANCED for buttons on tablets
val containerWidth = 300.smart().forElement(ElementType.CONTAINER).dp
// → Selects PERCENTAGE for containers| Element | Phone Strategy | Tablet Strategy | Rationale |
|---|---|---|---|
| BUTTON | DEFAULT (0.4) | BALANCED (0.7) | Consistent sizing |
| TEXT | FLUID (0.6) | FLUID (0.8) | Readable |
| ICON | DEFAULT (0.7) | DEFAULT (0.6) | Visual weight |
| CONTAINER | PERCENTAGE (0.8) | PERCENTAGE (0.8) | Proportional |
| SPACING | DEFAULT (0.5) | BALANCED (0.6) | Perceptual |
| ... | ... | ... | ... |
- PHONE_SMALL (< 300dp)
- PHONE_NORMAL (300-360dp)
- PHONE_LARGE (360-480dp)
- TABLET_SMALL (480-600dp)
- TABLET_LARGE (600-840dp)
- TV (840+dp)
- WATCH (< 240dp)
- AUTO (context-dependent)
Design for one orientation, automatically adapt when rotated:
// Android
val width = 300.balanced().portraitLowest().dp
// Portrait (360x800): Uses width (360)
// Landscape (800x360): Auto-inverts to width (800)
// iOS
let width = AppDimens.shared.balanced(300).portraitLowest().toPoints()
// Flutter
final width = AppDimens.balanced(300).portraitLowest().calculate(context);// Android
val buttonWidth = 10.mm // 10 millimeters
val cardWidth = 8.cm // 8 centimeters
val screenSize = 5.inch // 5 inches
// iOS
let width = AppDimensPhysicalUnits.mm(10)
// Flutter
final width = AppDimensPhysicalUnits.mmToPixels(10, context);Available: All platforms
📖 Physical Units Documentation
val games = AppDimensGames.getInstance()
games.initialize(context)
val buttonSize = games.calculateButtonSize(48f)
val playerSize = games.calculatePlayerSize(64f)Features: C++/NDK, OpenGL ES, Vector2D, Physical units
let buttonSize = gameUniform(48)
let playerSize = gameAspectRatio(64)Features: Metal/MetalKit, SIMD, 5 viewport modes
5x Overall Improvement:
| Optimization | v1.x | v2.0 | Speedup |
|---|---|---|---|
| Views cache | 0.005µs | 0.001µs | 5x |
| Ln() calculation | 0.012µs | 0.001µs | 10-20x |
| Memory/entry | 280B | 56B | 5x |
| Multi-thread | 25% | 100% | 4x |
// Global
AppDimens.setGlobalCache(true)
AppDimens.clearAllCaches()
// Per-instance
val size = AppDimens.balanced(48)
.cache(true)
.toDp(resources)// Call during app initialization
AppDimens.warmupCache(context)| Rank | Library/Strategy | Score | Category |
|---|---|---|---|
| 🏆 #1 | AppDimens BALANCED | 93/100 | Platinum |
| 🥈 #2 | AppDimens LOGARITHMIC | 88/100 | Platinum |
| 🥉 #3 | AppDimens POWER | 86/100 | Gold |
| #4 | AppDimens DEFAULT | 82/100 | Gold |
| #5 | AppDimens FLUID | 78/100 | Silver |
| ... | ... | ... | ... |
| #15 | SDP/SSP | 65/100 | Bronze |
| #18 | CSS vw/vh | 58/100 | Not Recommended |
| #20 | Traditional DP | 50/100 | Baseline |
| Aspect | AppDimens BALANCED ⭐ | SDP/SSP |
|---|---|---|
| Formula | Hybrid linear-log | Linear |
| Oversizing Control | 40% reduction | 0% |
| AR Compensation | No (BALANCED), Yes (DEFAULT) | No |
| Tablet (720dp) | 70dp ✅ | 115dp ❌ |
| Performance | 0.0012µs | 0.0000µs (pre-calc) |
| Flexibility | 13 strategies | 1 strategy |
| Files | 0 (runtime) | 426 XML files |
Recommendation: Migrate from SDP to BALANCED for 40% improvement
10,000 calculations benchmark:
| Strategy | Time (µs) | Relative |
|---|---|---|
| PERCENTAGE | 0.0003 | 1.0x (fastest) |
| POWER | 0.0008 | 2.7x |
| LOGARITHMIC | 0.0010 | 3.3x |
| BALANCED | 0.0012 | 4.0x |
| DEFAULT | 0.0015 | 5.0x |
All sub-microsecond! Negligible performance difference.
- Per cache entry: 56 bytes
- Total cache: ~60 KB
- Ln() lookup table: ~1 KB
- Total: ~61 KB (entire library)
Step 1: Update dependency to 2.0.0
Step 2: Replace .fxdp → .balanced().dp (or .defaultDp)
Step 3: Replace .dydp → .percentageDp.dp
Backward compatible: Old code still works!
Step 1: Add AppDimens dependency
Step 2: Replace @dimen/_16sdp → 16.balanced().dp
Step 3: Remove SDP dependency and XML files
Benefits: 40% better control, runtime flexibility
- CSS vw/vh → Use
balanced()orfluid() - ScreenUtil → Use
balanced() - size-matters → Use
balanced()orpower()
Android:
.balanced() // Primary ⭐
.defaultDp // Secondary
.percentageDp // Containers
.logarithmic() // TV
.power(n) // Configurable
.fluid(min, max) // Typography
.smart() // Auto-inferenceiOS:
.balanced(_)
.defaultScaling(_)
.percentage(_)
.logarithmic(_)
.power(_, exponent:)
.fluid(min:max:)
.smart(_)Flutter:
AppDimens.balanced(_)
AppDimens.defaultScaling(_)
AppDimens.percentage(_)
AppDimens.logarithmic(_)
AppDimens.power(_, exponent:)
AppDimens.fluid(_, maxValue:)
AppDimens.smart(_)// Custom screens
.screen(UiModeType.TV, 96.dp)
.screen(DpQualifier.SMALL_WIDTH, 600, 72.dp)
// Base orientation
.portraitLowest()
.landscapeHighest()
// Cache control
.cache(true)
// AR adjustment
.aspectRatio(enabled = true)Android:
.dp // Dp (Compose)
.sp // TextUnit (Compose)
.toDp() // Float (Views)
.toSp() // Float (Views)
.toPx() // Float (physical pixels)iOS:
.toPoints() // CGFloat
.toPt() // CGFloat (shorthand)
.toPixels() // CGFloat (physical)Flutter:
.calculate(context) // doubleQ: Sizes look wrong on my device
A: Check:
- Using correct strategy (BALANCED for multi-device)
- Base value is appropriate (48dp for buttons, not 16dp)
- Not mixing strategies randomly
Q: Performance seems slow
A: Solutions:
- Ensure cache is enabled (default)
- Call
warmupCache()during init - Use appropriate strategy (PERCENTAGE is fastest)
Q: Migration from v1.x - sizes changed
A:
.fxdpis now.defaultDp(same formula)- Try
.balanced()for better multi-device support - Old code still works (deprecated)
Q: Which strategy should I use?
A:
- Multi-device app → BALANCED ⭐
- Phone-only → DEFAULT
- Large containers → PERCENTAGE
- Typography → FLUID
Q: Is v2.0 compatible with v1.x?
A: Yes! 100% backward compatible. Old extensions still work.
Q: What's the performance impact?
A: Negligible (< 0.002µs per calculation with cache)
Q: Why is BALANCED now primary instead of DEFAULT?
A: BALANCED provides 40% better oversizing control on tablets while maintaining familiar linear behavior on phones. DEFAULT (formerly Fixed) is now optimized for phone-focused apps.
Q: Can I still use the old Fixed/Dynamic?
A: Yes! .fxdp and .dydp still work (deprecated). They map to .defaultDp and .percentageDp.
Q: When should I use PERCENTAGE instead of BALANCED?
A: Only for very large containers, images, and grids where proportional scaling is truly needed. For 95% of UI elements, use BALANCED.
Q: Is there overhead vs traditional DP?
A: Minimal (< 0.002µs with cache). Negligible in practice.
Q: Should I disable cache?
A: No, keep it enabled (default). Only disable for debugging.
Q: Does AppDimens work with Jetpack Compose?
A: Yes! Native Compose support with extension functions.
Q: Can I use AppDimens in XML layouts?
A: Yes! Use SDP/SSP modules for XML, or runtime calculation in code.
- Mathematical Theory - Complete math foundation
- Simplified Guide - 15min intro
- Formula Comparison - Rankings & analysis
- Examples - Code samples
- Weber, E. H. (1834). "De pulsu, resorptione, auditu et tactu"
- Fechner, G. T. (1860). "Elemente der Psychophysik"
- Stevens, S. S. (1957). "On the psychophysical law"
- Loomis et al. (1992). "Visual space perception"
Document created by: Jean Bodenberg
Last updated: February 2025
Version: 2.0.0
License: Apache 2.0
Repository: https://github.com/bodenberg/appdimens