Skip to content

Tired of screen fragmentation? AppDimens is the unified solution for responsive, pixel-perfect UI across all platforms and devices. It offers adaptive scaling (SDP, SSP, Dynamic, Fixed) for Kotlin, Compose, XML Views, Swift, and SwiftUI, ensuring layouts and fonts scale perfectly from the smallest to the largest device.

License

Notifications You must be signed in to change notification settings

bodenberg/appdimens

AppDimens - Responsive Design Across All Devices

๐Ÿ“ AppDimens

Smart Responsive Dimensions for Any Screen

Version License Platform Strategies

๐Ÿ“š Documentation | โšก Quick Reference | ๐Ÿ”ฌ Technical Details

Languages: English | Portuguรชs (BR) | Espaรฑol


๐Ÿ†• What's New in Version 2.0

๐ŸŽฏ 13 Scaling Strategies (up from 2!)

  • BALANCED โญ New recommended primary strategy - hybrid linear-logarithmic
  • DEFAULT (formerly Fixed) - logarithmic with aspect ratio (secondary recommendation)
  • PERCENTAGE (formerly Dynamic) - proportional scaling
  • LOGARITHMIC - pure Weber-Fechner psychophysics
  • POWER - Stevens' Power Law (configurable)
  • FLUID - CSS clamp-like with breakpoints
  • Plus 7 more: INTERPOLATED, DIAGONAL, PERIMETER, FIT, FILL, AUTOSIZE ๐Ÿ†•, NONE

๐Ÿง  Smart Inference System

  • Automatic strategy selection based on element type
  • 18 element types (BUTTON, TEXT, ICON, CONTAINER, etc.)
  • 8 device categories (PHONE_SMALL to TV)
  • Weight-based decision system

โšก 5x Performance Improvement

  • Unified lock-free cache (0.001ยตs)
  • Ln() lookup table (10-20x faster)
  • Pre-calculated constants
  • Binary search algorithms (O(log n))

โ™ป๏ธ Full Backward Compatibility

  • Old .fxdp/.dydp extensions still work
  • Smooth migration path to .balanced(), .defaultDp, .percentageDp

โšก Quick Overview

AppDimens makes your UI elements scale perfectly across all devices - from phones to tablets, TVs, watches, and web browsers.

Instead of fixed sizes that look tiny on tablets or huge on watches, AppDimens uses perceptual scaling based on psychophysics research (Weber-Fechner, Stevens) that adapts intelligently to screen size, aspect ratio, and device type.

Why AppDimens 2.0?

โŒ Without AppDimens:
   Phone (360dp): Button = 48dp (13% of screen) โœ… Good
   Tablet (720dp): Button = 48dp (7% of screen)  โŒ Too small!

โŒ With Linear Scaling (SDP):
   Phone (360dp): Button = 58dp (16% of screen) โœ… OK
   Tablet (720dp): Button = 115dp (16% of screen) โŒ Too big!

โœ… With AppDimens BALANCED โญ:
   Phone (360dp): Button = 58dp (16% of screen) โœ… Perfect
   Tablet (720dp): Button = 70dp (10% of screen) โœ… Perfect!

Key Benefits

  • โœ… Perfect proportions on any screen size
  • โœ… Works everywhere: Android, iOS, Flutter, React Native, Web
  • โœ… Simple API: .balanced(), .defaultDp, .percentageDp
  • โœ… Scientifically proven: Based on psychophysics research (Weber-Fechner, Stevens)
  • โœ… Best performance: 5x faster with lock-free cache and optimizations
  • โœ… 13 scaling strategies: From simple to advanced, covering all use cases
  • โœ… Smart Inference: Automatic strategy selection for 18 element types
  • โœ… Physical units: Real-world measurements (mm, cm, inch) across all platforms
  • โœ… Game development: Specialized modules for Android (C++/NDK) and iOS (Metal)
  • โœ… AutoSize ๐Ÿ†•: Container-aware auto-sizing like TextView autoSizeText

๐Ÿš€ Installation

Android

dependencies {
    // Core library (Fixed + Dynamic scaling + Physical Units)
    // Includes: .fxdp, .dydp, Physical Units (mm/cm/inch), Grid calculations
    implementation("io.github.bodenberg:appdimens-dynamic:2.0.0")
    
    // SDP scaling (Scalable DP for XML)
    // Includes: @dimen/_16sdp, etc.
    implementation("io.github.bodenberg:appdimens-sdps:2.0.0")
    
    // SSP scaling (Scalable SP for text in XML)
    // Includes: @dimen/_18ssp, etc.
    implementation("io.github.bodenberg:appdimens-ssps:2.0.0")
    
    // All-in-one (includes dynamic, sdps, ssps)
    // โš ๏ธ Note: Does NOT include games module
    implementation("io.github.bodenberg:appdimens-all:2.0.0")
    
    // Game development (C++/NDK + OpenGL)
    // ๐ŸŽฎ Separate dependency - not included in "all"
    implementation("io.github.bodenberg:appdimens-games:2.0.0")
}

iOS

CocoaPods:

# Full package (Main + UI)
pod 'AppDimens', '~> 2.0.0'

# Only Main module
pod 'AppDimens/Main', '~> 2.0.0'

# Games module (separate)
pod 'AppDimens/Games', '~> 2.0.0'

Swift Package Manager:

dependencies: [
    .package(url: "https://github.com/bodenberg/appdimens.git", from: "2.0.0")
]

Flutter

dependencies:
  appdimens: ^2.0.0

React Native

# npm
npm install [email protected]

# yarn
yarn add [email protected]

Web

# npm
npm install [email protected]

# yarn
yarn add [email protected]

# pnpm
pnpm add [email protected]

Vanilla JavaScript (CDN):

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/index.js"></script>
<script>
  const { balanced, defaultScaling, fluid } = WebDimens;
  
  document.getElementById('myElement').style.width = balanced(300);
</script>

๐Ÿ“– Complete Installation Guide


๐Ÿ’ก Basic Usage

Android (Jetpack Compose)

@Composable
fun MyCard() {
    Card(
        modifier = Modifier
            .width(300.balanced().dp)      // โœจ BALANCED (RECOMMENDED) โญ
            .padding(16.balanced().dp)     // โœจ Adapts intelligently
    ) {
        Text(
            text = "Hello World",
            fontSize = 18.balanced().sp    // โœจ Readable everywhere
        )
    }
}

Android (XML with SDP/SSP)

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="@dimen/_16sdp">
    
    <TextView
        android:layout_width="@dimen/_300sdp"
        android:layout_height="wrap_content"
        android:textSize="@dimen/_18ssp"
        android:text="Hello World" />
</LinearLayout>

Android (View Binding)

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        // BALANCED scaling (recommended) โญ
        val width = 300.balanced().toPx(resources)
        binding.card.layoutParams.width = width.toInt()
        
        // Physical units
        val margin = AppDimensPhysicalUnits.toCm(2f, resources)
        binding.button.setPadding(margin.toInt(), 0, margin.toInt(), 0)
    }
}

Android (Data Binding)

<!-- layout/activity_main.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    
    <data>
        <import type="com.appdimens.dynamic.compose.AppDimensExtKt"/>
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/_16sdp">
        
        <TextView
            android:layout_width="@dimen/_300sdp"
            android:layout_height="wrap_content"
            android:textSize="@dimen/_18ssp"
            android:text="Hello World" />
            
        <!-- Dynamic dimensions in DataBinding -->
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="@{AppDimensExtKt.balanced(48).dp}"
            android:text="Click Me" />
    </LinearLayout>
</layout>
// Activity with DataBinding
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityMainBinding = 
            DataBindingUtil.setContentView(this, R.layout.activity_main)
        
        // Set dimensions programmatically
        binding.button.apply {
            layoutParams.width = 200.balanced().toPx(resources).toInt()
            layoutParams.height = 56.balanced().toPx(resources).toInt()
        }
    }
}

Android (Physical Units - included in appdimens-dynamic)

// Use real-world measurements
// Physical Units are part of appdimens-dynamic
val cardWidth = AppDimensPhysicalUnits.toCm(8f, resources)  // 8 cm
val buttonHeight = AppDimensPhysicalUnits.toInch(0.5f, resources)  // 0.5 inch
val padding = AppDimensPhysicalUnits.toMm(10f, resources)  // 10 mm

view.layoutParams.width = cardWidth.toInt()
button.layoutParams.height = buttonHeight.toInt()
view.setPadding(padding.toInt(), padding.toInt(), padding.toInt(), padding.toInt())

// Grid calculations (also in appdimens-dynamic)
val spanCount = AppDimens.calculateAvailableItemCount(
    containerSizePx = recyclerView.width,
    itemSizeDp = 100f,
    itemMarginDp = 8f,
    resources = resources
)

Android (Games Module)

@Composable
fun GameScreen() {
    val gamesManager = remember { AppDimensGames.getInstance() }
    
    LaunchedEffect(Unit) {
        gamesManager.initialize(context)
    }
    
    Canvas(modifier = Modifier.fillMaxSize()) {
        // Game-specific dimensions
        val buttonSize = gamesManager.calculateButtonSize(48f)
        val playerSize = gamesManager.calculatePlayerSize(64f)
        
        // Draw game elements with scaled dimensions
        drawCircle(
            color = Color.Blue,
            radius = playerSize / 2
        )
    }
}

iOS (SwiftUI)

struct MyCard: View {
    var body: some View {
        VStack {
            Text("Hello World")
                .font(.system(size: AppDimens.shared.balanced(18).toPoints()))
        }
        .padding(AppDimens.shared.balanced(16).toPoints())
        .frame(width: AppDimens.shared.balanced(300).toPoints())
    }
}

iOS (UIKit)

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let containerView = UIView()
        containerView.backgroundColor = .systemBlue
        containerView.layer.cornerRadius = AppDimens.shared.balanced(16).toPoints()
        view.addSubview(containerView)
        
        let titleLabel = UILabel()
        titleLabel.text = "Hello World"
        titleLabel.font = .systemFont(ofSize: AppDimens.shared.balanced(18).toPoints())
        containerView.addSubview(titleLabel)
    }
}

Flutter

Widget build(BuildContext context) {
  return Container(
    width: AppDimens.balanced(300).calculate(context),
    padding: EdgeInsets.all(AppDimens.balanced(16).calculate(context)),
    child: Text(
      'Hello World',
      style: TextStyle(fontSize: AppDimens.balanced(18).calculate(context)),
    ),
  );
}

React Native

{% raw %}

function MyCard() {
  const { balanced } = useAppDimens();
  
  return (
    <View style={{ width: balanced(300), padding: balanced(16) }}>
      <Text style={{ fontSize: balanced(18) }}>
        Hello World
      </Text>
    </View>
  );
}

{% endraw %}

Web (Vanilla JavaScript)

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/index.js"></script>
</head>
<body>
  <div id="container">
    <header id="header">
      <h1 id="title">Hello World</h1>
    </header>
  </div>
  
  <script type="module">
    import { webdimens } from 'https://cdn.jsdelivr.net/npm/[email protected]/dist/index.mjs';
    
    // Apply balanced dimensions (recommended) โญ
    document.getElementById('header').style.height = webdimens.balanced(64);
    document.getElementById('title').style.fontSize = webdimens.balanced(24);
    document.getElementById('container').style.padding = webdimens.balanced(24);
  </script>
</body>
</html>

Web (React)

{% raw %}

import { useWebDimens } from 'webdimens/react';

function MyCard() {
  const { balanced, fluid } = useWebDimens();
  
  return (
    <div style={{ width: balanced(300), padding: balanced(16) }}>
      <h2 style={{ fontSize: fluid(18, 24) }}>Hello World</h2>
    </div>
  );
}

{% endraw %}

Web (Vue)

<template>
  <div :style="{ width: balanced(300), padding: balanced(16) }">
    <h2 :style="{ fontSize: balanced(18) }">Hello World</h2>
  </div>
</template>

<script setup>
import { useWebDimens } from 'webdimens/vue';

const { balanced } = useWebDimens();
</script>

Web (Svelte)

<script>
  import { webDimensStore } from 'webdimens/svelte';
  
  $: wd = $webDimensStore;
  $: width = wd.balanced(300);
  $: padding = wd.balanced(16);
  $: fontSize = wd.balanced(18);
</script>

<div style="width: {width}; padding: {padding};">
  <h2 style="font-size: {fontSize};">Hello World</h2>
</div>

Web (Angular)

import { Component } from '@angular/core';
import { WebDimensService } from 'webdimens/angular';

@Component({
  selector: 'app-card',
  template: `
    <div [ngStyle]="{ width: width, padding: padding }">
      <h2 [ngStyle]="{ fontSize: fontSize }">Hello World</h2>
    </div>
  `
})
export class CardComponent {
  width = '';
  padding = '';
  fontSize = '';

  constructor(private wd: WebDimensService) {
    this.width = wd.balanced(300);
    this.padding = wd.balanced(16);
    this.fontSize = wd.balanced(18);
  }
}

๐Ÿ“– More Examples


๐ŸŽฏ Scaling Strategies

AppDimens 2.0 offers 13 scaling strategies for different needs:

Strategy When to Use Example Availability
BALANCED โญ RECOMMENDED 95% of cases - multi-device apps (phones, tablets, TVs) 48.balanced().dp All platforms
DEFAULT (Secondary) Phone-focused apps, icons, backward compatibility 48.defaultDp All platforms
PERCENTAGE Large containers, full-width grids, proportional elements 100.percentageDp All platforms
LOGARITHMIC TV apps, maximum control on large screens 48.logarithmic() All platforms
POWER General purpose, configurable with exponent 48.power(0.75) All platforms
FLUID ๐ŸŒŠ Typography, spacing with smooth min/max transitions fluid(16, 24) All platforms
FIT / FILL Game UI (letterbox/cover) 48.fit() / 48.fill() All platforms
AUTOSIZE ๐Ÿ†• Container-aware auto-sizing (like TextView autoSizeText) smart().autosize() All platforms
INTERPOLATED Moderate scaling (50% linear) 48.interpolated() All platforms
DIAGONAL Scale based on screen diagonal (true physical size) 48.diagonal() All platforms
PERIMETER Scale based on W+H perimeter 48.perimeter() All platforms
NONE No scaling (constant size) 48.none() All platforms

๐Ÿ“– Understanding Scaling Strategies


๐Ÿ† Why AppDimens is #1

AppDimens was scientifically compared against 7 other scaling approaches:

๐Ÿฅ‡ #1 AppDimens BALANCED: 93/100 โญโญโญโญโญ (Primary recommendation)
๐Ÿฅˆ #2 AppDimens LOGARITHMIC: 88/100 โญโญโญโญโญ (TV/Large tablets)
๐Ÿฅ‰ #3 AppDimens POWER: 86/100 โญโญโญโญ
   #4 AppDimens DEFAULT: 82/100 โญโญโญโญ (Phone-focused)
   #5 SDP/SSP: 65/100
   #6 CSS vw/vh: 58/100

What Makes It Better?

  • โœ… BALANCED strategy: Hybrid linear-logarithmic (40% oversizing reduction)
  • โœ… Perceptual models: Based on psychophysics (Weber-Fechner, Stevens)
  • โœ… 13 strategies: Most comprehensive library
  • โœ… Smart Inference: Automatic strategy selection
  • โœ… 5x faster: Lock-free cache and optimizations
  • โœ… Aspect ratio compensation: Only library with AR adjustment (DEFAULT strategy)

๐Ÿ“Š See Full Comparison


๐Ÿ“š Documentation

Getting Started

  1. Quick Reference โšก Find anything in seconds
  2. Simplified Guide ๐Ÿ“– Understand in 15 minutes
  3. Examples ๐Ÿ’ป Ready-to-use code

Technical Documentation

  1. Complete Technical Guide ๐Ÿ”ฌ Everything in one place (2h read)
  2. Formula Comparison ๐Ÿ“Š Scientific analysis & rankings
  3. Mathematical Theory ๐Ÿ“ Formal mathematical foundation

Platform Guides

๐Ÿ“š Complete Documentation Index


๐ŸŽฎ Advanced Features

๐Ÿ†• Base Orientation (v1.2.0+)

Auto-adapt to screen rotation! Design for one orientation, automatically maintain proportions when rotated:

// Android - Design for portrait, auto-adapts to landscape
val cardWidth = 300.balanced().portraitLowest().dp
// Portrait (360x800):  Uses width (360) โœ…
// Landscape (800x360): Auto-inverts to width (800) โœ…

// Shorthand extensions
val padding = 16.balancedPortraitLowest    // Auto-inverts in landscape
val height = 200.balancedLandscapeHighest  // Auto-inverts in portrait
// iOS - Same concept
let cardWidth = AppDimens.shared.balanced(300).portraitLowest().toPoints()
// Flutter
final cardWidth = AppDimens.balanced(300).portraitLowest().calculate(context);

๐Ÿ“– Complete Base Orientation Guide

๐ŸŒŠ Fluid Scaling

Smooth interpolation between min/max values - perfect for typography and controlled growth:

// Android Compose - Font size 16-24sp between 320-768dp width
@Composable
fun FluidTypography() {
    val fontSize = fluidSp(16f, 24f)
    Text("Fluid Text", fontSize = fontSize)
    
    // With custom breakpoints
    val padding = fluidDp(8f, 16f, minWidth = 280f, maxWidth = 600f)
}
// iOS SwiftUI - Same concept
struct FluidView: View {
    var body: some View {
        Text("Fluid Text")
            .font(.system(size: AppDimens.shared.fluid(min: 16, max: 24).toPoints()))
            .padding(AppDimens.shared.fluid(min: 8, max: 16).toPoints())
    }
}
// Flutter
final fontSize = AppDimens.fluid(16, maxValue: 24).calculate(context);
final padding = AppDimens.fluid(8, maxValue: 16).calculate(context);

Availability: All platforms

When to use:

  • โœ… Typography with explicit bounds
  • โœ… Line heights and letter spacing
  • โœ… Smooth transitions across breakpoints
  • โŒ Not for general UI elements (use BALANCED instead)

Smart API with Auto-Inference ๐Ÿง 

Automatic strategy selection based on element type:

// Android - Automatic strategy selection
val buttonSize = 48.smart().forElement(ElementType.BUTTON).dp
// โ†’ Automatically selects BALANCED for buttons on tablets

val containerWidth = 300.smart().forElement(ElementType.CONTAINER).dp
// โ†’ Automatically selects PERCENTAGE for containers
// iOS
let buttonSize = AppDimens.shared.smart(48).forElement(.button).toPoints()
// Flutter
final buttonSize = AppDimens.smart(48).forElement(ElementType.button).calculate(context);

Custom Scaling Rules

// Android - Different sizes for different devices
val buttonSize = 56.balanced()
    .screen(UiModeType.TV, 96.dp)           // TVs: 96dp
    .screen(UiModeType.WATCH, 40.dp)        // Watches: 40dp
    .screen(DpQualifier.SMALL_WIDTH, 600, 72.dp)  // Tablets: 72dp
    .dp  // Others: auto-scaled from 56dp

๐Ÿ“ Physical Units

Real-world measurements across all platforms:

// Android - Physical units (mm, cm, inch)
val buttonWidth = 10.mm   // 10 millimeters
val cardWidth = 8.cm      // 8 centimeters
val screenSize = 5.inch   // 5 inches

// AppDimens Games also supports physical units
val playerSize = appDimensGames.mm(15f)  // 15mm player sprite
// iOS - Same API
let buttonWidth = AppDimensPhysicalUnits.mm(10)
let cardWidth = AppDimensPhysicalUnits.cm(8)
let screenSize = AppDimensPhysicalUnits.inch(5)
// Flutter
final buttonWidth = AppDimensPhysicalUnits.mmToPixels(10, context);
final cardWidth = AppDimensPhysicalUnits.cmToPixels(8, context);

Available everywhere: Android (Code + Compose), iOS (SwiftUI + UIKit), Flutter, React Native, Web

๐ŸŽฎ Game Development

Specialized high-performance modules for game development:

Android Games Module (C++/NDK)

val appDimensGames = AppDimensGames.getInstance()
appDimensGames.initialize(context)

// Game-specific dimension types
val buttonSize = appDimensGames.calculateButtonSize(48f)      // UI elements
val playerSize = appDimensGames.calculatePlayerSize(64f)      // Game world
val enemySize = appDimensGames.calculateEnemySize(32f)        // Game world
val uiOverlay = appDimensGames.calculateUISize(24f)           // HUD/Overlay

// Vector and Rectangle operations
val position = GameVector2D(100f, 200f)
val scaledPos = appDimensGames.calculateVector2D(position, GameDimensionType.GAME_WORLD)

val bounds = GameRectangle(0f, 0f, 800f, 600f)
val scaledBounds = appDimensGames.calculateRectangle(bounds, GameDimensionType.DYNAMIC)

// Physical units in games
val physicalSize = appDimensGames.cm(2f)  // 2cm for touch targets

Features:

  • โœ… Native C++/NDK for maximum performance
  • โœ… 4 dimension types: DYNAMIC, FIXED, GAME_WORLD, UI_OVERLAY
  • โœ… Vector2D and Rectangle utilities
  • โœ… OpenGL ES integration
  • โœ… Physical units support (mm, cm, inch)
  • โœ… Performance monitoring and optimization
  • โœ… Separate dependency - not included in appdimens-all

iOS Games Module (Metal)

// Metal/MetalKit integration
let buttonSize = gameUniform(48)           // Uniform scaling
let playerSize = gameAspectRatio(64)       // Aspect-ratio aware
let uiOverlay = gameViewport(24)           // Viewport-based

// SwiftUI Integration
struct GameView: View {
    var body: some View {
        MetalGameView()
            .frame(
                width: gameAspectRatio(320),
                height: gameAspectRatio(240)
            )
            .withAppDimens()
    }
}

Features:

  • โœ… Native Metal/MetalKit support
  • โœ… 5 viewport modes: Uniform, Horizontal, Vertical, AspectRatio, Viewport
  • โœ… SIMD extensions for performance
  • โœ… SwiftUI and UIKit compatible
  • โœ… Coordinate transformations (Screen โ†” NDC)

๐Ÿ“– Android Game Development Guide ๐Ÿ“– iOS Game Development Guide

โšก Global Cache Control

Control caching behavior globally across all AppDimens instances:

// Android - Global cache control
AppDimens.setGlobalCache(true)   // Enable (default)
AppDimens.setGlobalCache(false)  // Disable all caches
AppDimens.clearAllCaches()       // Clear all cached values

// Per-instance cache control
val dimension = AppDimens.balanced(100)
    .cache(true)  // Enable cache for this instance
    .toDp(resources)

// Check cache status
val isEnabled = AppDimens.isGlobalCacheEnabled()
// iOS - Same concept
AppDimensGlobal.globalCacheEnabled = true
AppDimensGlobal.clearAllCaches()

// Per-instance
let dimension = AppDimens.shared.balanced(100)
    .cache(true)
    .toPoints()
// Flutter
AppDimens.setGlobalCache(true);
AppDimens.clearAllCaches();

// Per-instance
final dimension = AppDimens.balanced(100)
    .cache(true)
    .calculate(context);

Features:

  • โœ… Global cache control affects all instances
  • โœ… Per-instance cache control for fine-tuning
  • โœ… Automatic cache invalidation on configuration changes
  • โœ… Zero performance overhead when disabled
  • โœ… Memory efficient with automatic cleanup

๐Ÿค Contributing

We welcome contributions!

๐Ÿ“– Contributing Guidelines


๐Ÿ“„ License

Apache License 2.0 - see LICENSE file


๐Ÿ‘จโ€๐Ÿ’ป Author

Jean Bodenberg


๐ŸŒŸ Support

If AppDimens helps your project:

  • โญ Star this repository
  • ๐Ÿฆ Share on social media
  • ๐Ÿ“ Write a review
  • ๐Ÿค Contribute to the project

Made with โค๏ธ for developers worldwide

Documentation โ€ข Examples โ€ข Technical Guide

About

Tired of screen fragmentation? AppDimens is the unified solution for responsive, pixel-perfect UI across all platforms and devices. It offers adaptive scaling (SDP, SSP, Dynamic, Fixed) for Kotlin, Compose, XML Views, Swift, and SwiftUI, ensuring layouts and fonts scale perfectly from the smallest to the largest device.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages