Universal Breakpoints
A simple, reusable, and platform-independent screen size breakpoints package for Flutter. Provides responsive design utilities for Android, iOS, Web, Windows, macOS, and Linux.
✨ Features
- Platform Agnostic: Works seamlessly on all Flutter platforms (Android, iOS, Web, Windows, macOS, Linux)
- 8 Main Breakpoint Categories: From ultra-small phones to 4K+ displays
- 19 Ultra-Granular Sub-Categories: Fine-grained control over specific device types
- Automatic Scaling: Built-in scaling factors for fonts, widths, and heights
- Responsive Extensions: Convenient BuildContext and num extensions
- Orientation Detection: Portrait/landscape and aspect ratio helpers
- Singleton Pattern: Single instance for consistent state across your app
- Dynamic Grid System: Responsive grid widgets with auto-adjusting columns, spacing, and animations
- Masonry Layouts: Pinterest-style masonry grid for varied item sizes
- Animated Grids: Multiple animation styles for grid item entrance effects
- Zero External Dependencies: All grid features use only Flutter's built-in widgets
🎨 Demo & Documentation
- 📚 Full Documentation - Complete API reference, guides, and examples
- 🎮 Interactive Demo - Try Universal Breakpoints in action
🚀 Getting Started
Installation
Add to your pubspec.yaml:
dependencies:
universal_breakpoints: ^1.0.0
Then run:
flutter pub get
Basic Setup
Initialize in your main app widget:
import 'package:universal_breakpoints/universal_breakpoints.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
UniversalBreakpoints().init(context);
return MaterialApp(
title: 'My App',
home: const MyHome(),
);
}
}
Using ResponsiveWrapper for Dynamic Updates
The ResponsiveWrapper widget automatically handles screen size changes and rebuilds your UI dynamically when the device is resized or rotated. This is especially useful for web applications and desktop apps where users can resize the window.
Instead of manually initializing UniversalBreakpoints in each widget, wrap your app with ResponsiveWrapper:
import 'package:universal_breakpoints/universal_breakpoints.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ResponsiveWrapper(
config: ResponsiveWrapperConfig(
autoInitialize: true,
debugPrint: false, // Set to true for resize debug logs
),
child: MaterialApp(
title: 'My App',
home: const MyHome(),
),
);
}
}
How it works:
- Automatically initializes
UniversalBreakpointson each rebuild - Listens to Flutter's
MediaQuerysystem for screen size changes - Triggers widget rebuilds whenever the screen is resized or orientation changes
- All descendant widgets automatically get responsive properties updated
- Optional debug logging to monitor resize events
Example with debug enabled:
ResponsiveWrapper(
config: ResponsiveWrapperConfig(
autoInitialize: true,
debugPrint: true, // Logs resize events to console
),
child: MyApp(),
)
💻 Usage
1. BuildContext Extensions
class MyHome extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Responsive App')),
body: context.isMobile
? const MobileLayout()
: context.isTablet
? const TabletLayout()
: const DesktopLayout(),
);
}
}
2. Conditional Rendering
class ResponsiveWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(context.isDesktop ? 32 : 16),
child: Column(
children: [
if (context.isMobile) Text('Mobile View'),
if (context.isTablet) Text('Tablet View'),
if (context.isDesktop) Text('Desktop View'),
],
),
);
}
}
3. Responsive Values
class GridLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
int columns = context.responsiveValue<int>(
mobile: 1,
smallTablet: 2,
largeTablet: 3,
desktop: 4,
);
return GridView.count(
crossAxisCount: columns,
children: List.generate(12, (index) => Container()),
);
}
}
4. Scaling Extensions
class ScaledText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
'Large Title',
style: TextStyle(fontSize: 32.sF),
),
Text(
'Body Text',
style: TextStyle(fontSize: 16.sF, height: 16.sFh),
),
SizedBox(
width: 200.sW,
height: 100.sH,
child: Container(),
),
],
);
}
}
5. Orientation-Specific Layouts
class OrientationAwareWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return context.isPortrait
? PortraitLayout()
: LandscapeLayout();
}
}
📖 API Reference
Screen Size Categories
context.isXXS // Extra extra small (< 360px)
context.isXS // Extra small (360-479px)
context.isSM // Small (480-767px)
context.isMD // Medium (768-1023px)
context.isLG // Large (1024-1279px)
context.isXL // Extra large (1280-1439px)
context.isXXL // Extra extra large (1440-1919px)
context.isXXXL // Ultra large (1920+px)
Device Type Detection
context.isMobile // < 768px
context.isTablet // 768-1279px
context.isDesktop // 1280+px
context.isLargeScreen // 1440+px
Ultra-Granular Sub-Categories
context.isUltraCompact // < 320px
context.isCompactPhone // 320-374px
context.isStandardPhone // 375-413px
context.isLargePhone // 414-479px
context.isPhablet // 480-567px
context.isSmallTablet // 568-667px
context.isStandardTablet // 668-767px
context.isLargeTablet // 768-833px
context.isExtraLargeTablet // 834-1023px
context.isSmallDesktop // 1024-1279px
context.isStandardDesktop // 1280-1365px
context.isLargeDesktop // 1366-1439px
context.isExtraLargeDesktop // 1440-1535px
context.isWidescreen // 1536-1679px
context.isFullHD // 1680-1919px
context.isQHD // 1920-2559px
context.isUltraWide // 2560-3439px
context.isUltraHD // 3440-3839px
context.isSuperUltraWide // 3840+px
Orientation & Aspect Ratio
context.isPortrait // Height > Width
context.isLandscape // Width > Height
context.isUltraWideAspect // Aspect ratio > 2.0
context.isStandardAspect // Aspect ratio 1.3-1.8
context.isTallAspect // Aspect ratio < 1.3
Scaling Extensions
16.sF // Scaled font size
100.sW // Scaled width
50.sH // Scaled height
14.sFh // Calculated line height
Direct Access
final config = UniversalBreakpoints();
config.screenWidth // Current screen width
config.screenHeight // Current screen height
config.textScaleFactor // Font scaling factor
config.widthScaleFactor // Width scaling factor
config.heightScaleFactor // Height scaling factor
config.screenType // Type as string
config.screenSizeCategory // Main category
config.screenSizeSubCategory // Sub-category
config.scaledFontSize(16) // Scale font size
config.scaledWidth(100) // Scale width
config.scaledHeight(50) // Scale height
📏 Breakpoint Values
| Category | Breakpoint | Range | Purpose |
|---|---|---|---|
| xxs | 360px | 0-359px | Extra small phones |
| xs | 480px | 360-479px | Small phones |
| sm | 768px | 480-767px | Large phones |
| md | 1024px | 768-1023px | Tablets |
| lg | 1280px | 1024-1279px | Large tablets/desktops |
| xl | 1440px | 1280-1439px | Desktop |
| xxl | 1920px | 1440-1919px | Large desktop |
| xxxl | 2560px | 1920+px | 4K+ displays |
🎯 Advanced Examples
Complex Responsive Layout
class ComplexResponsiveLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(context.isMobile ? 16.0 : 32.0),
child: Column(
children: [
Text(
'Welcome',
style: TextStyle(
fontSize: context.isMobile ? 24.sF : 32.sF,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20.sH),
GridView.count(
crossAxisCount: context.responsiveValue<int>(
mobile: 1,
tablet: 2,
desktop: 3,
),
mainAxisSpacing: 16.sH,
crossAxisSpacing: 16.sW,
children: List.generate(9, (index) {
return Container(
width: double.infinity,
height: context.isMobile ? 150.sH : 200.sH,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.blue[100],
),
);
}),
),
],
),
),
);
}
}
Adaptive Navigation
class AdaptiveNavigation extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (context.isMobile) {
return BottomNavigationBar(
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
);
} else if (context.isTablet) {
return Row(
children: [
NavigationRail(destinations: [...]),
Expanded(child: Content()),
],
);
} else {
return Row(
children: [
SideNavigation(),
Expanded(child: Content()),
],
);
}
}
}
🔲 Dynamic Grid System
Universal Breakpoints includes a powerful dynamic grid system with multiple responsive grid widgets. All features use only Flutter's built-in widgets—no external dependencies required.
Basic Dynamic Grid
The DynamicGrid widget automatically adjusts columns, spacing, and sizing based on screen breakpoints.
DynamicGrid(
items: List.generate(12, (index) => index),
itemBuilder: (context, item, index) {
return Card(
child: Center(child: Text('Item ${index + 1}')),
);
},
columnConfig: GridColumnConfig(
smallMobile: 1,
mobile: 1,
largeMobile: 2,
tablet: 3,
desktop: 4,
largeDesktop: 6,
),
spacingConfig: GridSpacingConfig(
smallMobile: 8,
mobile: 12,
tablet: 16,
desktop: 24,
),
enableAnimations: true,
)
Features:
- Auto-adjusting column count per breakpoint
- Responsive item spacing
- Smooth animations on layout changes
- Customizable aspect ratio for items
- Optional SliverGrid support for custom scroll behavior
Masonry Grid
Create Pinterest-style masonry layouts that adapt to different screen sizes.
MasonryDynamicGrid(
items: List.generate(20, (index) => index),
itemBuilder: (context, item, index) {
return Card(child: Center(child: Text('$item')));
},
columnConfig: GridColumnConfig(
mobile: 2,
tablet: 3,
desktop: 4,
),
spacingConfig: GridSpacingConfig(defaultSpacing: 12),
)
Features:
- Natural column-based masonry layout
- Responsive column count
- Flexible item heights
- Smooth animations
Animated Grid
Display grid items with smooth entrance animations. Choose from multiple animation styles.
AnimatedDynamicGrid(
items: List.generate(12, (index) => index),
itemBuilder: (context, item, index) {
return Card(child: Center(child: Text('Item $index')));
},
columnConfig: GridColumnConfig(
mobile: 1,
tablet: 2,
desktop: 3,
),
itemStyle: AnimatedGridItemStyle.fadeAndScale,
animationDuration: const Duration(milliseconds: 500),
)
Animation Styles:
scaleIn: Items scale up on entrancefadeIn: Items fade in smoothlyslideInFromLeft: Items slide from the leftslideInFromTop: Items slide from the topfadeAndScale: Combined fade and scale effect
Grid Configuration
GridColumnConfig
Fine-tune column counts for each device size:
GridColumnConfig(
ultraCompact: 1,
compact: 1,
standard: 2,
largePhone: 2,
phablet: 2,
smallTablet: 3,
largeTablet: 3,
smallDesktop: 4,
standardDesktop: 5,
largeDesktop: 6,
ultraWide: 8,
)
GridSpacingConfig
Customize spacing at different breakpoints:
GridSpacingConfig(
ultraCompactSpacing: 4,
compactSpacing: 8,
standardSpacing: 12,
largePhoneSpacing: 12,
tabletSpacing: 16,
desktopSpacing: 24,
ultraWideSpacing: 40,
)
Dynamic Grid Properties
DynamicGrid(
items: [], // Required: List of items
itemBuilder: (context, item, i) {}, // Required: Widget builder
columnConfig: GridColumnConfig(...), // Optional: Custom columns
spacingConfig: GridSpacingConfig(...), // Optional: Custom spacing
itemAspectRatio: 1.0, // Default: square items
enableAnimations: true, // Default: true
animationDuration: Duration(...), // Default: 300ms
animationCurve: Curves.easeInOut, // Default curve
useSliverGrid: false, // Use SliverGrid instead
scrollPhysics: BouncingScrollPhysics(), // Scroll behavior
padding: EdgeInsets.all(16), // Grid padding
mainAxisSpacing: 12, // Override spacing
crossAxisSpacing: 12, // Override spacing
)
Real-World Example
class ProductGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DynamicGrid(
items: products,
itemBuilder: (context, product, index) {
return ProductCard(product: product);
},
columnConfig: GridColumnConfig(
mobile: 1,
largeMobile: 2,
tablet: 3,
desktop: 4,
largeDesktop: 6,
),
spacingConfig: GridSpacingConfig(
mobile: 8,
tablet: 12,
desktop: 16,
defaultSpacing: 12,
),
itemAspectRatio: 0.75,
padding: EdgeInsets.all(16.0),
enableAnimations: true,
);
}
}
↩️ Backwards Compatibility
For code using the old SizeConfig name:
typedef SizeConfig = UniversalBreakpoints;
SizeConfig().init(context); // Still works
UniversalBreakpoints().init(context); // New name
✅ Platform Support
- Android
- iOS
- Web (Chrome, Firefox, Safari, Edge)
- Windows
- macOS
- Linux
📦 Package Info
- Minimal Dependencies: Only depends on Flutter
- Zero Configuration: Works out of the box
- Production Ready: Used in multiple production applications
- Fully Documented: Complete API documentation
🤝 Contributing
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
📄 License
MIT License - See LICENSE file for details.
For more information, visit pub.flutter-io.cn