simple_responsive_layout 1.1.0 copy "simple_responsive_layout: ^1.1.0" to clipboard
simple_responsive_layout: ^1.1.0 copied to clipboard

A super lightweight Flutter package for simple mobile, tablet, and desktop responsive layouts.

📱 simple_responsive_layout #

A minimal, powerful Flutter package for building responsive layouts, widgets, values, and visibility without the bloat.

✨ Features #

  • 🧩 ResponsiveChild – Switch a single widget's layout based on device type
  • 🏗️ ResponsiveLayout – Switch container layouts (Row ↔ Column ↔ Grid) based on device
  • 🔢 ResponsiveValue – Dynamically select values based on device type
  • 🫥 ResponsiveVisibility – Show/hide widgets on specific device types
  • 📏 ResponsiveSizedBox – Flexible sizing based on device type
  • 🛣️ ResponsivePadding – Adaptive padding based on device type
  • 🧰 ResponsiveBuilder – Full control with custom builder and responsive info
  • 🔄 ResponsiveOrientationChild – Switch layouts based on portrait or landscape mode
  • 💫 ResponsiveOrientationValue – Values that adapt to device orientation
  • ⚙️ ResponsiveSettings – Customize breakpoints
  • 🔄 ResponsiveInfo – Complete device information with helpful properties
  • Zero dependencies — pure Flutter implementation
  • Extremely lightweight and fast

🚀 Usage #

Basic Setup (Optional) #

While the package works with default settings, you can customize breakpoints globally:

void main() {
  // Optional: Configure global responsive settings
  ResponsiveSettings.defaultSettings = ResponsiveSettings(
    mobileWidth: 600,     // breakpoint between mobile and tablet
    tabletWidth: 1024,    // breakpoint between tablet and desktop
  );
  
  runApp(const MyApp());
}

Provider Setup (Optional) #

For more advanced projects, you can use the provider to manage settings:

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return ResponsiveSettingsProvider(
      settings: ResponsiveSettings(
        mobileWidth: 550,
        tabletWidth: 1200,
      ),
      child: MaterialApp(
        title: 'My Responsive App',
        home: HomePage(),
      ),
    );
  }
}

ResponsiveChild #

Switch a single widget's layout based on device:

ResponsiveChild(
  child: Text('Hello World'),
  mobileChild: (context, child) => Center(
    child: child,
  ),
  tabletChild: (context, child) => Align(
    alignment: Alignment.centerLeft,
    child: child,
  ),
  desktopChild: (context, child) => Container(
    padding: EdgeInsets.all(16),
    child: child,
  ),
)

Or build the child dynamically:

ResponsiveChild(
  childBuilder: (context, info) => Text(
    info.isMobileOnly 
      ? 'Mobile View' 
      : info.isTabletOnly 
          ? 'Tablet View' 
          : 'Desktop View',
    style: TextStyle(
      fontSize: info.isMobile ? 16 : info.isTablet ? 20 : 24,
    ),
  ),
)

ResponsiveLayout #

Switch how a group of widgets are arranged:

ResponsiveLayout(
  children: [
    Card(child: Text('Item 1')),
    Card(child: Text('Item 2')),
    Card(child: Text('Item 3')),
  ],
  mobileChild: (context, children) => Column(
    children: children,
  ),
  tabletChild: (context, children) => Row(
    children: children,
  ),
  desktopChild: (context, children) => Wrap(
    spacing: 16,
    runSpacing: 16,
    children: children,
  ),
)

Or dynamically generate different children based on device:

ResponsiveLayout(
  childrenBuilder: (context, info) => [
    Text('Header'),
    if (info.isMobile) 
      const SizedBox(height: 20),
    if (!info.isMobile) 
      const SizedBox(width: 20),
    Text('Content'),
    if (info.isDesktopOnly) 
      Text('Desktop-only content'),
  ],
  mobileChild: (context, children) => Column(children: children),
  tabletChild: (context, children) => Row(children: children),
)

ResponsiveValue #

Choose dynamic values based on device type:

// In a widget:
final fontSize = ResponsiveValue<double>(
  defaultValue: 16.0,
  mobileValue: 14.0,
  tabletValue: 16.0,
  desktopValue: 18.0,
).value(context);

Text(
  'Hello World',
  style: TextStyle(fontSize: fontSize),
)

Or with custom logic:

final padding = ResponsiveValue<EdgeInsets>(
  defaultValue: EdgeInsets.all(16),
  valueBuilder: (context, info) {
    // Full custom logic for any scenario
    if (info.isMobileOnly) {
      return EdgeInsets.all(8);
    } else if (info.isTabletOnly) {
      return EdgeInsets.symmetric(horizontal: 24, vertical: 16);
    } else {
      return EdgeInsets.symmetric(horizontal: 32, vertical: 20);
    }
  },
).value(context);

ResponsiveVisibility #

Show or hide widgets for different device types:

// Only visible on mobile and tablet
ResponsiveVisibility(
  deviceTypes: [ResponsiveDeviceType.mobile, ResponsiveDeviceType.tablet],
  child: FloatingActionButton(
    onPressed: () {},
    child: Icon(Icons.add),
  ),
)

// Only visible on desktop
ResponsiveVisibility(
  deviceTypes: [ResponsiveDeviceType.desktop],
  child: Row(
    children: [
      Icon(Icons.settings),
      Text('Advanced Settings'),
    ],
  ),
)

ResponsiveSizedBox #

Different sizes for spacing based on device:

// Vertical gap that changes based on device
ResponsiveSizedBox(
  defaultSize: const Size(double.infinity, 16),
  mobileSize: const Size(double.infinity, 8),
  tabletSize: const Size(double.infinity, 16),
  desktopSize: const Size(double.infinity, 24),
)

// Or with child
ResponsiveSizedBox(
  mobileSize: const Size(double.infinity, 100),
  tabletSize: const Size(300, double.infinity),
  desktopSize: const Size(500, double.infinity),
  child: Text('Sized content'),
)

ResponsivePadding #

Adaptive padding based on device:

ResponsivePadding(
  defaultSize: EdgeInsets.all(16),
  mobileSize: EdgeInsets.all(8),
  tabletSize: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
  desktopSize: EdgeInsets.symmetric(horizontal: 32, vertical: 20),
  child: Card(
    child: Text('Content with device-specific padding'),
  ),
)

NEW in v1.1.0: Orientation Support #

ResponsiveOrientationChild

Adapt your widget layout based on portrait or landscape orientation:

ResponsiveOrientationChild(
  child: Text('Hello World'),
  portraitChild: (context, child) => Center(
    child: Container(
      width: 300,
      child: child,
    ),
  ),
  landscapeChild: (context, child) => Align(
    alignment: Alignment.centerLeft,
    child: Container(
      width: 500,
      child: child,
    ),
  ),
)

ResponsiveOrientationValue

Select different values based on device orientation:

// In a widget:
final padding = ResponsiveOrientationValue<EdgeInsets>(
  defaultValue: EdgeInsets.all(16),
  portraitValue: EdgeInsets.symmetric(horizontal: 16, vertical: 24),
  landscapeValue: EdgeInsets.symmetric(horizontal: 32, vertical: 8),
).value(context);

Container(
  padding: padding,
  child: Text('Orientation-aware padding'),
)

Combining Device Type and Orientation #

You can easily combine device type and orientation responsiveness:

// First adapt to device type, then to orientation
ResponsiveChild(
  // Device type first
  mobileChild: (context, child) => Container(
    color: Colors.blue,
    // Then orientation for the mobile layout
    child: ResponsiveOrientationChild(
      child: child,
      portraitChild: (ctx, c) => Padding(
        padding: EdgeInsets.all(8),
        child: c,
      ),
      landscapeChild: (ctx, c) => Padding(
        padding: EdgeInsets.all(16),
        child: c,
      ),
    ),
  ),
  desktopChild: (context, child) => Container(
    color: Colors.green,
    child: child,
  ),
  child: Text('Responsive content'),
)

Or use orientation-aware values in device-specific layouts:

ResponsiveValue<TextStyle>(
  // Default style
  defaultValue: TextStyle(fontSize: 16),
  // Mobile style with orientation-specific sizes
  mobileValue: TextStyle(
    fontSize: ResponsiveOrientationValue<double>(
      defaultValue: 14,
      portraitValue: 14,
      landscapeValue: 12,
    ).value(context),
  ),
  // Desktop style
  desktopValue: TextStyle(fontSize: 18),
).value(context)

ResponsiveBuilder #

For complete custom control:

ResponsiveBuilder(
  builder: (context, info) {
    // Full access to device info for custom layouts
    if (info.isMobile) {
      // Check orientation for mobile layouts
      if (info.isPortrait) {
        return Column(
          children: [
            Text('Mobile Portrait Layout'),
            // Portrait-specific widgets
          ],
        );
      } else {
        return Row(
          children: [
            Text('Mobile Landscape Layout'),
            // Landscape-specific widgets
          ],
        );
      }
    } else if (info.isTablet) {
      // Similar tablet orientation checks
      // ...
    } else {
      // Desktop layout
      return Row(
        children: [
          Expanded(
            flex: 1,
            child: Text('Sidebar'),
          ),
          Expanded(
            flex: 4,
            child: Text('Main Content'),
          ),
          Expanded(
            flex: 1,
            child: Text('Additional Sidebar'),
          ),
        ],
      );
    }
  },
)

🧠 Understanding ResponsiveInfo #

The ResponsiveInfo class now includes orientation information:

ResponsiveBuilder(
  builder: (context, info) {
    // Device type information
    print('Device type: ${info.deviceType}');
    
    // Orientation information
    print('Is portrait: ${info.isPortrait}');
    print('Is landscape: ${info.isLandscape}');
    print('Orientation: ${info.orientation}');
    
    // Device type properties
    print('Is mobile: ${info.isMobile}');
    print('Is tablet: ${info.isTablet}');
    print('Is desktop: ${info.isDesktop}');

    return Text('Device: ${info.deviceType}, Orientation: ${info.orientation}');
  },
)

⚙️ Customizing Settings #

Global Settings #

// Change the global defaults
ResponsiveSettings.defaultSettings = ResponsiveSettings(
  mobileWidth: 480,    // Smaller mobile breakpoint
  tabletWidth: 1024,   // Standard tablet breakpoint
);

Local Settings Override #

You can override settings for specific widgets:

final myCustomSettings = ResponsiveSettings(
  mobileWidth: 400,
  tabletWidth: 800,
);

// Apply to a specific widget
ResponsiveChild(
  settings: myCustomSettings,
  child: Text('Custom breakpoints apply here'),
  // ...
)

📏 How Device Detection Works #

Simple MediaQuery width-based detection:

Device Type Width Range
Mobile < mobileWidth (default: 600px)
Tablet >= mobileWidth && < tabletWidth
Desktop >= tabletWidth (default: 1024px)

Orientation is determined using MediaQuery:

final orientation = MediaQuery.of(context).orientation == Orientation.portrait
    ? ResponsiveOrientation.portrait
    : ResponsiveOrientation.landscape;

🏆 Example with Orientation Support #

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

class OrientationAwareWidget extends StatelessWidget {
  const OrientationAwareWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return ResponsiveBuilder(
      builder: (context, info) {
        // Check both device type and orientation
        if (info.isMobile) {
          return ResponsiveOrientationChild(
            // Portrait layout for mobile
            portraitChild: (ctx, child) => Column(
              children: [
                Text('Mobile Portrait', 
                  style: TextStyle(fontSize: 20)),
                child,
              ],
            ),
            // Landscape layout for mobile
            landscapeChild: (ctx, child) => Row(
              children: [
                Expanded(
                  flex: 1,
                  child: Text('Mobile Landscape', 
                    style: TextStyle(fontSize: 16)),
                ),
                Expanded(
                  flex: 2,
                  child: child,
                ),
              ],
            ),
            // The content that will be placed in the layout
            child: Container(
              padding: ResponsiveOrientationValue<EdgeInsets>(
                defaultValue: EdgeInsets.all(16),
                portraitValue: EdgeInsets.all(24),
                landscapeValue: EdgeInsets.symmetric(horizontal: 8, vertical: 16),
              ).value(context),
              color: Colors.amber[200],
              child: Text('Content area'),
            ),
          );
        } else if (info.isTablet) {
          // Tablet layout with orientation handling
          // ...
        } else {
          // Desktop layout
          return Container(
            padding: EdgeInsets.all(32),
            color: Colors.purple[100],
            child: Text('Desktop Layout'),
          );
        }
      },
    );
  }
}

📄 License #

MIT License.
Free for personal and commercial use.

❤️ Why simple_responsive_layout? #

  • No unnecessary complexity - Lightweight yet powerful
  • Full control when you need it - Override anything
  • Tiny package size - No dependency bloat
  • Pure Flutter philosophy - No extras required
  • Perfect for any project size - From small apps to enterprise projects

🎯 Conclusion #

Simple. Clean. Powerful Flutter responsiveness.

📦 Coming soon #

  • AnimatedResponsive widgets for smooth transitions
  • Additional responsive helpers (ResponsiveGridView, etc.)
  • Media query shortcuts for more device metrics
  • More orientation-specific widgets and utilities

🛡️ Status #

✅ Production ready
✅ No known issues
✅ Backed by real-world Flutter projects

🙌 Contributing #

If you like this package, ⭐️ star it on GitHub, share it, or contribute!

1
likes
160
points
203
downloads

Publisher

verified publisherexpd.co.uk

Weekly Downloads

A super lightweight Flutter package for simple mobile, tablet, and desktop responsive layouts.

Repository (GitHub)
View/report issues

Topics

#responsive #layout #flutter #adaptive #mobile

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on simple_responsive_layout