flutter_screenutil_plus

flutter_screenutil_plus

Flutter Package Pub Points License

A powerful Flutter plugin for adapting screen and font size with CSS-like breakpoints and SwiftUI-like size classes. Let your UI display a reasonable layout on different screen sizes!

โœจ Features

  • ๐Ÿ“ฑ Responsive Scaling: Automatic scaling of width, height, font size, and more
  • โšก InheritedWidget-Based Scope: Efficient, targeted rebuilds with ScreenUtilPlusScope
  • ๐ŸŽฏ Context-Aware Extensions: New context.w(), context.h(), context.sp() for optimal performance
  • ๐ŸŽจ CSS-like Breakpoints: Media query-style breakpoints (Bootstrap, Tailwind, Material Design)
  • ๐Ÿ“ SwiftUI-like Size Classes: Compact/Regular size classes for adaptive layouts
  • ๐Ÿงฉ Adaptive Widgets: Breakpoint-aware containers, text, and builders
  • ๐Ÿš€ Performance Optimized: Intelligent rebuild detection with optional autoRebuild: false
  • ๐ŸŽญ Responsive Theme: Automatic text style scaling in themes
  • ๐Ÿ“ฆ Zero Configuration: Works out of the box with sensible defaults
  • ๐Ÿงช Well Tested: 99.2% code coverage with 619 tests

๐Ÿ“ฆ Installation

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_screenutil_plus: ^1.4.0

Then run:

flutter pub get

๐Ÿš€ Quick Start

1. Initialize the Library

Wrap your app with ScreenUtilPlusInit:

import 'package:flutter_screenutil_plus/flutter_screenutil_plus.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScreenUtilPlusInit(
      designSize: const Size(360, 690),
      minTextAdapt: true,
      splitScreenMode: true,
      builder: (context, child) {
        return MaterialApp(
          title: 'Flutter ScreenUtil Plus',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: child,
        );
      },
      child: const HomePage(),
    );
  }
}

2. Use Responsive Extensions

Container(
  width: 100.w,   // Responsive width
  height: 50.h,   // Responsive height
  padding: EdgeInsets.all(16.r), // Responsive padding
  child: Text(
    'Hello World',
    style: TextStyle(fontSize: 16.sp), // Responsive font
  ),
)

2. Use Responsive Extensions

Container(
  width: 100.w,   // Responsive width
  height: 50.h,   // Responsive height
  padding: EdgeInsets.all(16.r), // Responsive padding
  child: Text(
    'Hello World',
    style: TextStyle(fontSize: 16.sp), // Responsive font
  ),
)

For better performance with autoRebuild: false, use context-aware extensions:

Container(
  width: context.w(100),   // Context-aware width
  height: context.h(50),   // Context-aware height
  padding: context.edgeInsets(all: 16), // Context-aware padding
  child: Text(
    'Hello World',
    style: TextStyle(fontSize: context.sp(16)), // Context-aware font
  ),
)

๐Ÿš€ Performance Optimization (v1.4.0)

InheritedWidget-Based Scope

Version 1.4.0 introduces ScreenUtilPlusScope for efficient, targeted rebuilds:

ScreenUtilPlusInit(
  designSize: const Size(360, 690),
  autoRebuild: false,  // ๐ŸŽฏ NEW: Disable automatic tree-wide rebuilds
  builder: (context, child) {
    return MaterialApp(
      home: child,
    );
  },
  child: HomePage(),
)

Benefits of autoRebuild: false:

  • โšก Significantly faster - Only widgets that need responsive values rebuild
  • ๐ŸŽฏ Targeted updates - Only widgets using context.w(), context.su, or R-widgets rebuild
  • ๐Ÿ”„ Backward compatible - Defaults to true for existing apps

Context-Aware Extensions

When using autoRebuild: false, use context-aware extensions for optimal performance:

// โœ… Recommended with autoRebuild: false
context.w(100)          // Scale width
context.h(50)           // Scale height
context.r(20)           // Scale radius
context.sp(16)          // Scale font size
context.spMin(12)       // Scale font with minimum
context.dg(100)         // Scale diagonal
context.dm(100)         // Scale diameter

// Spacing helpers
context.verticalSpace(20)      // Vertical spacing
context.horizontalSpace(20)    // Horizontal spacing

// Complex values
context.edgeInsets(all: 16)    // Scaled EdgeInsets
context.edgeInsets(             // Custom EdgeInsets
  horizontal: 16,
  vertical: 8,
)
context.borderRadius(all: 12)  // Scaled BorderRadius

// Access ScreenUtilPlus instance
final su = context.su;         // Get ScreenUtilPlus instance

Migration to Context-Aware Extensions

// โŒ Old way (still works, but rebuilds entire tree)
Container(width: 100.w, height: 50.h)

// โœ… New way (efficient with autoRebuild: false)
Container(width: context.w(100), height: context.h(50))

When to use each:

  • autoRebuild: true (default): Use .w, .h, .sp extensions - simpler syntax
  • autoRebuild: false: Use context.w(), context.h(), context.sp() - better performance

๐Ÿ“š Core Features

Responsive Extensions

The package provides extension methods for easy responsive sizing:

// Width and Height
100.w    // Adapt to screen width
100.h    // Adapt to screen height
100.r    // Adapt to smaller of width/height (radius)
100.dm   // Adapt to larger of width/height (diameter)
100.dg   // Adapt based on diagonal calculation

// Font Size
16.sp    // Responsive font size
16.spMin // min(16, 16.sp) - prevents font from being too large
16.spMax // max(16, 16.sp) - ensures minimum font size

// Screen Dimensions
1.sw     // Screen width
1.sh     // Screen height

// Spacing Helpers
20.verticalSpace      // SizedBox(height: 20 * scaleHeight)
20.horizontalSpace    // SizedBox(width: 20 * scaleWidth)

Responsive Widgets

Pre-built widgets that automatically apply scaling:

// Responsive Container
RContainer(
  width: 100,
  height: 50,
  padding: EdgeInsets.all(8),
  child: Text('Responsive'),
)

// Responsive Padding
RPadding(
  padding: EdgeInsets.all(16),
  child: Text('Padded'),
)

// Responsive SizedBox
RSizedBox(width: 100, height: 50)

// Responsive Text (auto-scales fontSize)
RText('Hello', style: TextStyle(fontSize: 16))

๐ŸŽฏ CSS-like Breakpoints

Create responsive designs similar to CSS media queries.

Using Breakpoints

// Get current breakpoint
final breakpoint = context.breakpoint; // xs, sm, md, lg, xl, xxl

// Check breakpoints
if (context.isAtLeast(Breakpoint.md)) {
  // Tablet and larger
}

if (context.isLessThan(Breakpoint.lg)) {
  // Smaller than desktop
}

if (context.isBetween(Breakpoint.sm, Breakpoint.lg)) {
  // Between small and large
}

Predefined Breakpoint Sets

// Bootstrap 5 (default)
Breakpoints.bootstrap  // xs: 0, sm: 576, md: 768, lg: 992, xl: 1200, xxl: 1400

// Tailwind CSS
Breakpoints.tailwind  // sm: 640, md: 768, lg: 1024, xl: 1280, xxl: 1536

// Material Design
Breakpoints.material  // sm: 600, md: 960, lg: 1280, xl: 1920, xxl: 2560

// Mobile-first
Breakpoints.mobileFirst  // sm: 480, md: 768, lg: 1024, xl: 1440, xxl: 1920

// Custom breakpoints
const customBreakpoints = Breakpoints(
  xs: 0,
  sm: 480,
  md: 768,
  lg: 1024,
  xl: 1440,
);

ResponsiveBuilder

Build different layouts for different breakpoints:

ResponsiveBuilder(
  xs: (context) => MobileLayout(),
  sm: (context) => MobileLandscapeLayout(),
  md: (context) => TabletLayout(),
  lg: (context) => DesktopLayout(),
  xl: (context) => LargeDesktopLayout(),
)

AdaptiveContainer

Container that adapts properties based on breakpoints:

AdaptiveContainer(
  width: {
    Breakpoint.xs: 100,
    Breakpoint.md: 200,
    Breakpoint.lg: 300,
  },
  padding: {
    Breakpoint.xs: EdgeInsets.all(8),
    Breakpoint.md: EdgeInsets.all(16),
    Breakpoint.lg: EdgeInsets.all(24),
  },
  child: Text('Adaptive Container'),
)

// Or use SimpleAdaptiveContainer for easier syntax
SimpleAdaptiveContainer(
  widthXs: 100,
  widthMd: 200,
  widthLg: 300,
  paddingXs: 8,
  paddingMd: 16,
  child: Text('Simple Adaptive'),
)

Responsive Queries

Get values based on breakpoints:

final query = ResponsiveQuery.of(context);

// Get value based on current breakpoint
final padding = query.value(
  xs: 8.0,
  sm: 12.0,
  md: 16.0,
  lg: 24.0,
);

// Or use AdaptiveValues for responsive sizing
final adaptive = AdaptiveValues.of(context);
final width = adaptive.width(xs: 50, sm: 100, md: 150, lg: 200);
final fontSize = adaptive.fontSize(xs: 12, sm: 14, md: 16, lg: 18);

๐Ÿ“ SwiftUI-like Size Classes

Create adaptive layouts using size classes (similar to SwiftUI).

Using Size Classes

// Get size classes
final sizeClasses = context.sizeClasses;

// Check size classes
if (sizeClasses.isRegular) {
  // Regular size (e.g., iPad)
}

if (sizeClasses.isCompact) {
  // Compact size (e.g., iPhone in portrait)
}

// Check individual dimensions
if (sizeClasses.isRegularHorizontal) {
  // Wide screen
}

if (sizeClasses.isCompactVertical) {
  // Short screen
}

SizeClassBuilder

Build different layouts based on size classes:

SizeClassBuilder(
  compact: (context) => CompactLayout(),
  regular: (context) => RegularLayout(),
)

// Or with horizontal/vertical size classes
SizeClassBuilder(
  horizontal: (context, horizontal) {
    return horizontal == SizeClass.regular
        ? WideLayout()
        : NarrowLayout();
  },
  vertical: (context, vertical) {
    return vertical == SizeClass.regular
        ? TallLayout()
        : ShortLayout();
  },
)

// Or with full size class information
SizeClassBuilder(
  builder: (context, sizeClasses) {
    return Text(
      'H: ${sizeClasses.horizontal}, V: ${sizeClasses.vertical}',
    );
  },
)

Custom Threshold

SizeClassBuilder(
  threshold: 600, // Custom threshold (default: 600)
  compact: (context) => CompactLayout(),
  regular: (context) => RegularLayout(),
)

๐ŸŽจ Adaptive Text Styles

Create text styles that adapt based on breakpoints:

// Using context extension
final style = context.adaptiveTextStyle(
  xs: TextStyle(fontSize: 12, color: Colors.black),
  md: TextStyle(fontSize: 16, color: Colors.blue),
  lg: TextStyle(fontSize: 20, color: Colors.green),
);

// Using AdaptiveText widget
AdaptiveText(
  'Adaptive Text',
  xs: TextStyle(fontSize: 12),
  md: TextStyle(fontSize: 16),
  lg: TextStyle(fontSize: 20),
)

// Using TextStyle extensions
TextStyle(fontSize: 16)
  .r  // Makes fontSize responsive
  .withLineHeight(1.5)  // Sets line height
  .withAutoLineHeight()  // Auto-calculates line height

๐Ÿ”ง Advanced Usage

Conditional Rendering

ConditionalBuilder(
  condition: (context) => context.isAtLeast(Breakpoint.md),
  builder: (context) => DesktopLayout(),
  fallback: (context) => MobileLayout(),
)

Responsive Theme

Automatically scale all text styles in your theme:

ScreenUtilPlusInit(
  designSize: const Size(360, 690),
  builder: (context, child) {
    return MaterialApp(
      theme: ResponsiveTheme.fromTheme(
        ThemeData(
          primarySwatch: Colors.blue,
          textTheme: TextTheme(
            headlineLarge: TextStyle(fontSize: 24),
            bodyLarge: TextStyle(fontSize: 16),
          ),
        ),
      ),
      home: child,
    );
  },
  child: HomePage(),
)

Properties

Property Type Default Value Description
designSize Size Size(360,690) The size of the device screen in the design draft, in dp
autoRebuild bool true NEW in v1.4.0: When false, only widgets using context-aware extensions or context.su rebuild on screen changes (improves performance)
builder Function null Return widget that uses the library in a property (ex: MaterialApp's theme)
child Widget null A part of builder that its dependencies/properties don't use the library
rebuildFactor RebuildFactor RebuildFactors.size Function that takes old and new screen metrics and returns whether to rebuild or not when changes occur. See RebuildFactors
splitScreenMode bool false Support for split screen mode
minTextAdapt bool false Whether to adapt the text according to the minimum of width and height
ensureScreenSize bool false Whether to wait for screen size to be initialized before building (useful for web/desktop)
fontSizeResolver FontSizeResolver FontSizeResolvers.width Function that specifies how font size should be adapted. See FontSizeResolvers
responsiveWidgets Iterable null List/Set of widget names that should be included in rebuilding tree. (See How flutter_screenutil_plus marks a widget needs build)
enableScaleWH Function null Function to enable/disable scaling of width and height
enableScaleText Function null Function to enable/disable scaling of text

Note : You must either provide builder, child or both.

Rebuild Factors

The rebuildFactor parameter controls when the widget tree should rebuild based on MediaQuery changes. Available options:

  • RebuildFactors.size (default) - Rebuild when screen size changes
  • RebuildFactors.orientation - Rebuild when orientation changes
  • RebuildFactors.sizeAndViewInsets - Rebuild when view insets change
  • RebuildFactors.change - Rebuild on any MediaQuery change
  • RebuildFactors.always - Always rebuild
  • RebuildFactors.none - Never rebuild automatically

You can also provide a custom function:

rebuildFactor: (oldData, newData) => oldData.size != newData.size

Font Size Resolvers

The fontSizeResolver parameter controls how font sizes are calculated. Available options:

  • FontSizeResolvers.width (default) - Scale based on screen width
  • FontSizeResolvers.height - Scale based on screen height
  • FontSizeResolvers.radius - Scale based on the smaller of width/height
  • FontSizeResolvers.diameter - Scale based on the larger of width/height
  • FontSizeResolvers.diagonal - Scale based on diagonal calculation

You can also provide a custom function:

fontSizeResolver: (fontSize, instance) => instance.setWidth(fontSize * 0.9)

Rebuild List

Starting from version 1.0.0, ScreenUtilInit won't rebuild the whole widget tree, instead it will mark widget needs build only if:

  • Widget is not a flutter widget (widgets are available in Flutter Docs)
  • Widget does not start with underscore (_)
  • Widget does not declare SU mixin
  • responsiveWidgets does not contains widget name

If you have a widget that uses the library and doesn't meet these options you can either add SU mixin or add widget name in responsiveWidgets list.

Using the SU Mixin

To mark a custom widget for automatic rebuilding, use the SU mixin:

import 'package:flutter_screenutil_plus/flutter_screenutil_plus.dart';

class MyCustomWidget extends StatelessWidget with SU {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100.w,
      height: 50.h,
      child: Text('Responsive', style: TextStyle(fontSize: 16.sp)),
    );
  }
}

Enable or Disable Scaling

Widget build(BuildContext context) {
  return ScreenUtilPlusInit(
    enableScaleWH: () => false,  // Disable width/height scaling
    enableScaleText: () => false, // Disable text scaling
    //...
  );
}

or

ScreenUtilPlus.enableScale(
  enableWH: () => false,
  enableText: () => false
);

Device Type Detection

You can detect the device type for platform-specific UI adjustments:

final deviceType = ScreenUtilPlus().deviceType(context);
switch (deviceType) {
  case DeviceType.mobile:
    // Mobile-specific UI
    break;
  case DeviceType.tablet:
    // Tablet-specific UI
    break;
  case DeviceType.web:
    // Web-specific UI
    break;
  // ... other device types
}

API Reference

Extension Methods

Extension Description Example
.w Adapt to screen width 100.w
.h Adapt to screen height 100.h
.r Adapt to smaller of width/height 100.r
.dm Adapt to larger of width/height 100.dm
.dg Adapt based on diagonal 100.dg
.sp Responsive font size 16.sp
.spMin Minimum font size 12.spMin
.spMax Maximum font size 16.spMax
.sw Screen width 1.sw
.sh Screen height 1.sh

Context Extensions

Extension Description Example
Context-Aware (v1.4.0)
context.w(value) Scale width context.w(100)
context.h(value) Scale height context.h(50)
context.r(value) Scale radius context.r(20)
context.sp(value) Scale font size context.sp(16)
context.spMin(value) Scale font with minimum context.spMin(12)
context.dg(value) Scale diagonal context.dg(100)
context.dm(value) Scale diameter context.dm(100)
context.verticalSpace() Create vertical spacing context.verticalSpace(20)
context.horizontalSpace() Create horizontal spacing context.horizontalSpace(20)
context.edgeInsets() Create scaled EdgeInsets context.edgeInsets(all: 16)
context.borderRadius() Create scaled BorderRadius context.borderRadius(all: 12)
context.su Get ScreenUtilPlus instance context.su
Breakpoints
context.breakpoint Current breakpoint context.breakpoint
context.isAtLeast() Check if at least breakpoint context.isAtLeast(Breakpoint.md)
context.isLessThan() Check if less than breakpoint context.isLessThan(Breakpoint.lg)
context.isBetween() Check if between breakpoints context.isBetween(Breakpoint.sm, Breakpoint.lg)
Size Classes
context.sizeClasses Get size classes context.sizeClasses
Utilities
context.adaptive() Get AdaptiveValues context.adaptive()
context.responsive() Get ResponsiveQuery context.responsive()
context.mediaQueryData Get MediaQueryData context.mediaQueryData

Widgets

Widget Description
ScreenUtilPlusInit Initialize the library
RContainer Responsive Container
RPadding Responsive Padding
RSizedBox Responsive SizedBox
RText Responsive Text
AdaptiveContainer Breakpoint-aware Container
SimpleAdaptiveContainer Simplified adaptive container
AdaptiveText Breakpoint-aware Text
ResponsiveBuilder Builder for different breakpoints
SizeClassBuilder Builder for size classes
ConditionalBuilder Conditional rendering

Performance Optimizations

Starting from version 1.1.1, the package includes intelligent change detection using Equatable to optimize rebuilds:

  • Automatic change detection: Only rebuilds registered elements when screen metrics actually change
  • Value-based equality: Uses Equatable to compare screen configuration state efficiently
  • Reduced unnecessary rebuilds: Prevents rebuilds when configuration remains functionally identical

This optimization is automatic and requires no code changes. The package will only trigger rebuilds when:

  • Screen size changes
  • Orientation changes
  • Split screen mode changes
  • Minimum text adaptation setting changes
  • Font size resolver function changes

๐Ÿ’ก Best Practices

  1. Set design size once: Initialize ScreenUtilPlusInit at the root of your app
  2. Use .r for squares: Use .r extension when you want perfect squares
  3. Use breakpoints for major layout changes: Use ResponsiveBuilder for different layouts
  4. Use size classes for adaptive UI: Use SizeClassBuilder for SwiftUI-like adaptive layouts
  5. Combine with responsive widgets: Use AdaptiveContainer for breakpoint-aware properties
  6. Test on multiple devices: Always test your responsive design on different screen sizes

๐ŸŽฏ Complete Example

import 'package:flutter/material.dart';
import 'package:flutter_screenutil_plus/flutter_screenutil_plus.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScreenUtilPlusInit(
      designSize: const Size(360, 690),
      minTextAdapt: true,
      builder: (context, child) {
        return MaterialApp(
          title: 'Flutter ScreenUtil Plus',
          theme: ResponsiveTheme.fromTheme(
            ThemeData(
              primarySwatch: Colors.blue,
              textTheme: TextTheme(
                headlineLarge: TextStyle(fontSize: 24),
                bodyLarge: TextStyle(fontSize: 16),
              ),
            ),
          ),
          home: child,
        );
      },
      child: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter ScreenUtil Plus'),
      ),
      body: ResponsiveBuilder(
        xs: (context) => _MobileLayout(),
        md: (context) => _TabletLayout(),
        lg: (context) => _DesktopLayout(),
      ),
    );
  }
}

class _MobileLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SingleColumnLayout();
  }
}

class _TabletLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return TwoColumnLayout();
  }
}

class _DesktopLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ThreeColumnLayout();
  }
}

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments

  • Inspired by flutter_screenutil
  • Breakpoint system inspired by CSS media queries
  • Size class system inspired by SwiftUI

๐Ÿ“ž Support


Made with โค๏ธ by Muhammad Kamel

Libraries

flutter_screenutil_plus
A Flutter plugin for adapting screen and font size.