📦 smart_sizer

A lightweight and flexible Flutter package that helps you build responsive UIs based on a fixed reference screen size. Automatically scale width, height, font size, and more for all devices.

📱📲📺 Adapt your app beautifully on mobile, tablet, and desktop.


🚀 Installation

dependencies:
  smart_sizer: ^1.1.1

Then:

flutter pub get

✅ Usage

1️⃣ Wrap your app with SizeBuilder in MyHomePage:

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

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

class MyHomePage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return   SizeBuilder(
          baseSize: Size(360, 690),
          height: context.screenHeight,
          width: context.screenWidth,
          child: MaterialApp(
      
            debugShowCheckedModeBanner: false,
            home : MainScreen(),
          ));
  }
}

2️⃣ Use extension methods inside your widgets:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          width: context.getWidth(60),
          height: context.getHeight(20),
          color: Colors.blue,
          child: Text(
            'Hello Ahmed',
            style: TextStyle(fontSize: context.getFontSize(16)),
          ),
        ),
      ),
    );
  }
}

More example


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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.all(context.getWidth(24)),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Login',
              style: TextStyle(
                fontSize: context.getFontSize(22),
                fontWeight: FontWeight.bold,
              ),
            ),
            SizedBox(height: context.getHeight(20)),
            TextField(
              decoration: InputDecoration(
                hintText: 'Email',
                contentPadding: EdgeInsets.symmetric(
                  horizontal: context.getWidth(16),
                  vertical: context.getHeight(12),
                ),
              ),
            ),
            SizedBox(height: context.getHeight(16)),
            TextField(
              decoration: InputDecoration(
                hintText: 'Password',
                contentPadding: EdgeInsets.symmetric(
                  horizontal: context.getWidth(16),
                  vertical: context.getHeight(12),
                ),
              ),
            ),
            SizedBox(height: context.getHeight(24)),
            ElevatedButton(
              onPressed: () {},
              style: ElevatedButton.styleFrom(
                padding: EdgeInsets.symmetric(
                  vertical: context.getHeight(14),
                  horizontal: context.getWidth(40),
                ),
              ),
              child: Text(
                'Submit',
                style: TextStyle(fontSize: context.getFontSize(16)),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

3️⃣ Use DeviceUtils methods inside your widgets:



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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Responsive GridView")),
      backgroundColor: AppColors.accent,
      body: Padding(
        padding: EdgeInsets.all(context.getWidth(12)),
        child: GridView.builder(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            // Use GridView to All OS and Device
            crossAxisCount: DeviceUtils.valueDecider(
              context,
              onMobile: 2,
              onTablet: 3,
              onDesktop: 4,
            ),
            crossAxisSpacing: context.getWidth(10),
            mainAxisSpacing: context.getHeight(10),
            childAspectRatio: 1, 
          ),
          itemCount: 20,
          itemBuilder: (context, index) {
            return Container(
              alignment: Alignment.center,
              decoration: BoxDecoration(
                color: Colors.blue,
                borderRadius: BorderRadius.circular(context.getMinSize(12)),
              ),
              child: Text(
                "Item ${index + 1}",
                style: TextStyle(
                  fontSize: context.getFontSize(14),
                  color: Colors.white,
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

4️⃣ Use SizeBuilder in card widgets :


/// 📄 Example screen: A responsive ListView of Cards
/// This screen demonstrates how to create a **responsive list of cards**
/// using `SizeBuilder` and `smart_sizer` utilities.
/// 
/// Features:
/// ✅ Each card adapts in height, width, and font size 🪄
/// ✅ Includes interactive tap and button actions 🎯
/// ✅ Example of using `context.getFontSize`, `context.getWidth`, and `context.getHeight`
/// 
/// Perfect for showing lists, menus, or catalog items 📋

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

  
  @override
  Widget build(BuildContext context) {

 final items = List.generate(12, (i) => {
      'title': 'Card title ${i + 1}',
      'subtitle': 'This is a brief description of item ${i + 1}.',
      'icon': Icons.widgets,
    });

    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Responsive Cards',
          style: TextStyle(fontSize: context.getFontSize(18)),
        ),
      ),
      body: Container(

        height: context.sizeBuilder.height,
        child: SizeBuilder( baseSize: Size(250,250),
          height: context.getMinSize(250),
          width: context.getMinSize(250),
          child:  Builder(builder: (context) {
            return SizedBox(

              child: ListView.builder(

                padding: EdgeInsets.only(
                  top: context.getHeight(12),
                  bottom: context.getHeight(12),
                ),
                itemCount: items.length,

                itemBuilder: (context, index) {
                  final item = items[index];
                  return Card(

                    elevation: 4,
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(context.getMinSize(14)),
                    ),
                    child: InkWell(
                      onTap: () {
                  
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(content: Text('Tapped ${item['title']}')),
                        );
                      },
                      borderRadius: BorderRadius.circular(context.getMinSize(14)),
                      child: SizedBox(
                        height: context.sizeBuilder.height/2 ,

                        child: Padding(
                          padding: EdgeInsets.symmetric(
                            horizontal: context.getWidth(12),
                            vertical: context.getHeight(12),
                          ),
                          child: Row(
                            children: [

                              CircleAvatar(
                                radius: context.getMinSize(28),
                                backgroundColor: Theme.of(context).colorScheme.primary.withOpacity(0.12),
                                child: Icon(
                                  item['icon'] as IconData,
                                  size: context.getFontSize(20),
                                  color: Theme.of(context).colorScheme.primary,
                                ),
                              ),

                              SizedBox(width: context.getWidth(12)),


                              Expanded(
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text(
                                      item['title'] as String,
                                      style: TextStyle(
                                        fontSize: context.getFontSize(16),
                                        fontWeight: FontWeight.w700,
                                      ),
                                    ),
                                    SizedBox(height: context.getHeight(6)),
                                    Text(
                                      item['subtitle'] as String,
                                      style: TextStyle(
                                        fontSize:  context.getFontSize(14),
                                        color: Theme.of(context).textTheme.bodySmall?.color?.withOpacity(0.8),
                                      ),
                                      maxLines: 2,
                                      overflow: TextOverflow.ellipsis,
                                    ),
                                  ],
                                ),
                              ),

                              SizedBox(width: context.getWidth(12)),
                              ElevatedButton(
                                onPressed: () {
                                
                                  ScaffoldMessenger.of(context).showSnackBar(
                                    SnackBar(content: Text('Action for ${item['title']}')),
                                  );
                                },
                                style: ElevatedButton.styleFrom(
                                  padding: EdgeInsets.symmetric(
                                    horizontal: context.getWidth(6),
                                    vertical: context.getHeight(6),
                                  ),
                                  shape: RoundedRectangleBorder(
                                    borderRadius: BorderRadius.circular(8),
                                  ),
                                ),
                                child: Text(
                                  'Open',
                                  style: TextStyle(fontSize: context.getFontSize(12)),
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  );
                },
              ),
            );

          },),

                ),
      ),);
  }
}


📐 Available Extensions

Extension Description
context.getWidth(x) Scaled width from reference design
context.getHeight(x) Scaled height from reference design
context.getFontSize(x) Font size scaled to screen
context.getMinSize(x) Minimum scaling factor
context.scaleWidth Current width ratio to base
context.scaleHeight Current height ratio to base
context.isMobile Is device considered mobile
context.isTablet Is device a tablet
context.isDesktop Is device desktop
context.safePadding Safe area (notch, status bar, etc)

💡 Why use smart_sizer?

  • Simple and predictable scaling
  • Easy to integrate into any Flutter project
  • Breakpoint support (mobile / tablet / desktop)
  • Useful for localization and text scaling

📄 License

MIT © 2025 Ahmed Shaker

Built with ❤️ for responsive design enthusiasts


For help or contributions, feel free to open issues or PRs on GitHub.

📬 Suggestions? Contact me at GitHub page placeholder.

Libraries

smart_sizer