responsive_scaler 1.0.1
responsive_scaler: ^1.0.1 copied to clipboard
A Flutter package for consistent responsive scaling of text, icons, and spacing based on screen size, helping maintain UI proportionality across devices.
Responsive Scaler #
Responsive Scaler is a lightweight, zero-boilerplate scaling engine for Flutter. It provides a linear, clamped scaling system that ensures your UI remains proportional across mobile, tablet, and desktop without the overhead of manual wrapping or step-based breakpoints.
💎 Key Value Propositions #
- Zero-Boilerplate Text: Initialize once; all
Textwidgets scale automatically. No.spor.fontSizewrappers required. - Linear Scaling Engine: Smooth transitions between screen sizes. No "jarring" jumps when resizing windows.
- Advanced Clamping: Industry-first "Double-Layer" clamping (Global + Local) to prevent UI implosion on tiny screens or explosion on 4K monitors.
- Accessibility Guardrails: Deep integration with
TextScalerthat respects system settings while capping maximum growth to prevent layout breakage. - The "Radius" Philosophy: Uses the shortest-side logic (
.r) to ensure padding and icons remain consistent even in landscape orientation.
📊 The Responsive Landscape #
| Feature | Responsive Scaler | ScreenUtil | Responsive Framework |
|---|---|---|---|
| Text Scaling | Automatic (Global Injection) | Manual (16.sp) |
Breakpoint-based (Not linear) |
| Effort | Set & Forget | High (Wrap every value) | Medium (Layout logic focus) |
| Scaling Style | Smooth Linear | Smooth Linear | Step-based Jumps |
| Safety | Global + Local Clamping | None (Manual only) | Range-based |
| Primary Goal | Component Scaling | Pixel Perfection | Adaptive Layouts |
Pro Tip: Use Responsive Scaler for scaling (fonts, icons, spacing) and Responsive Framework for adaptive layouts (changing a Column to a Row). They are the perfect combo.
⚠️ Migration & Breaking Changes (v0.1.0) #
Important
The global scale() function (e.g., scale(50)) has been removed.
You must now use the extension methods on num types.
// OLD (Removed)
scale(50)
// NEW Extension Methods
// From previous version
50.scale() // Defaults to width-based scale
50.scale(type: ScaleType.width, minValue: 100, maxValue: 300)
// ----- RECOMMENDED -----
// Shorthands
50.w // Width-based
50.h // Height-based
50.r // Radius/Minimum-based
// With Clamping
50.wc(minValue: 100, maxValue: 300) // Width-based with clamping
50.hc(minValue: 50) // Height-based with clamping
50.rc(minValue: 25) // Radius-based with clamping
📦 Installation #
Add this to your package's pubspec.yaml file:
dependencies:
responsive_scaler: ^latest_version
Then run flutter pub get.
🛠 Getting Started #
1. Initialize the Scaler #
In your main.dart, call ResponsiveScaler.init() before runApp().
You must provide the designWidth and designHeight from your design file (e.g., Figma).
import 'package:responsive_scaler/responsive_scaler.dart';
void main() {
ResponsiveScaler.init(
designWidth: 375, // e.g., iPhone Design Width
designHeight: 812, // e.g., iPhone Design Height
minScale: 0.8, // Optional: Minimum scale factor (default 0.8)
maxScale: 1.4, // Optional: Maximum scale factor (default 1.4)
maxAccessibilityScale: 1.8, // Optional: Limit for system text scaling
);
runApp(const MyApp());
}
2. Apply Scaling to the App #
Wrap your app using ResponsiveScaler.scale in the MaterialApp builder.
Note
Set useMaxAccessibility: true to enable the accessibility clamping feature configured in init().
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, child) {
return ResponsiveScaler.scale(
context: context,
child: child!,
useMaxAccessibility: true, // Enables accessibility clamping
);
},
home: const HomePage(),
);
}
}
📖 Usage Guide #
1. Automatic Text Scaling #
Once initialized, standard Text widgets scale automatically. You don't need to do anything special.
Note
Do not use const with Text widgets
// This text automatically scales based on screen width/height
// No `const` should be used!!
// Reason: `const` widgets are "frozen" and won't listen to the MediaQuery updates
// that drive the responsive scaling.
Text(
'Hello World',
style: TextStyle(fontSize: 16),
)
// OR
Text(
'Hello World',
style: Theme.of(context).textTheme.headlineMedium,
)
2. Scaling Sizes & Spacing #
For non-text elements (containers, icons, padding), use the extension methods on num.
Basic Extensions
| Extension | Meaning | Best Used For |
|---|---|---|
.w |
Width-based scale | Horizontal widths, margins, padding |
.h |
Height-based scale | Vertical heights, margins, padding |
.r |
Radius-based scale (Min of W/H) | Icons, circular avatars, square containers |
Container(
width: 100.w, // Scales with screen width
height: 200.h, // Scales with screen height
padding: EdgeInsets.all(16.r), // Scales evenly
);
Clamped Scaling (.wc, .hc, .rc)
Use these to prevent UI elements from becoming too small or too large, regardless of the screen size.
// Width scaled, but never smaller than 100 or larger than 300
width: 200.wc(minValue: 100, maxValue: 300),
// Height scaled, but never smaller than 50
height: 100.hc(minValue: 50),
3. Responsive Spacing [DEPRECATED] #
Use ResponsiveSpacing for consistent gaps between widgets.
Warning
The Grid System: Both horizontal (w) and vertical (h) spacers use the radius (.r) scaling logic.
This means hMedium and wMedium return the exact same pixel value, creates a perfectly symmetrical visual grid.
RECOMMENDED to define manual numbers since this is DEPRECATED and will be removed in future versions.
Column(
children: [
Text("Title"),
SizedBox(height: ResponsiveSpacing.hMedium), // Vertical gap
Text("Subtitle"),
],
)
| Constant | Description | Value |
|---|---|---|
hXSmall / wXSmall |
Extra Small | 4.r |
hSmall / wSmall |
Small | 8.r |
hMedium / wMedium |
Medium | 16.r |
hLarge / wLarge |
Large | 24.r |
hXLarge / wXLarge |
Extra Large | 32.r |
🔍 Deep Dive: Under the Hood #
How does Responsive Scaler actually calculate sizes?
1. The Core Calculation #
The scaler calculates a ratio based on the current screen size vs. your design size.
$$ Scale_{width} = \frac{\text{Current Screen Width}}{\text{Design Width}} $$
$$ Scale_{height} = \frac{\text{Current Screen Height}}{\text{Design Height}} $$
2. Clamping Logic #
To prevent UI from breaking on extremely large (tablets/desktop) or small (watches/mini) screens, the calculated scale factor is clamped.
FinalScale = clamp(CalculatedScale, minScale, maxScale)
Defined in init().
3. The "Radius" Scale (.r) #
For elements that should maintain their aspect ratio (like Icons or square Avatars), we use the Scaling Radius. This is simply the minimum of the width and height scales.
RadiusScale = min(WidthScale, HeightScale)
This ensures that an icon doesn't grow disproportionately huge just because the device is very tall (like a foldable) or very wide (like a tablet).
4. Accessibility Protection #
For Text, we multiply the RadiusScale by the user's System Text Scale (from OS settings).
However, if useMaxAccessibility is enabled, we apply a safety cap:
FinalTextScale = min(RadiusScale * SystemScale, maxAccessibilityScale)
This ensures that even if a user sets their phone to "Huge Text", your app's layout won't break completely, while still respecting their need for larger text.
🏗️ Built with Responsive Scaler #
Check out this project to see the package in action:
- muditpurohit.tech – A portfolio website that stays perfectly proportioned from mobile to desktop.