Debug School

rakesh kumar
rakesh kumar

Posted on

How to make responsive layout in flutter

Use MediaQuery for Sizing
Replace all hardcoded sizes with percentages of screen width/height:

double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;

// Example: Button width is 80% of screen width, but min 180, max 350
double buttonWidth = screenWidth * 0.8;
if (buttonWidth < 180) buttonWidth = 180;
if (buttonWidth > 350) buttonWidth = 350;
Enter fullscreen mode Exit fullscreen mode

B. Use SafeArea and SingleChildScrollView
This ensures content is always visible and scrollable, even on small screens:

body: SafeArea(
  child: SingleChildScrollView(
    child: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          // ...your widgets...
        ],
      ),
    ),
  ),
),
Enter fullscreen mode Exit fullscreen mode

C. Responsive Button Example

Column(
  children: countryData.keys.map((countryName) {
    return GestureDetector(
      onTap: () => _onCountrySelected(countryName),
      child: Container(
        width: buttonWidth,
        padding: EdgeInsets.symmetric(
          vertical: screenHeight * 0.015,
          horizontal: 20,
        ),
        margin: EdgeInsets.symmetric(
          vertical: screenHeight * 0.008,
        ),
        decoration: BoxDecoration(
          color: Color(int.parse(countryData[countryName]!['color']!)),
          borderRadius: BorderRadius.circular(10),
          border: Border.all(
            color: _selectedCountryName == countryName ? Colors.white : Colors.grey,
          ),
        ),
        child: Text(
          countryName,
          style: TextStyle(
            fontSize: screenWidth * 0.045,
            fontWeight: FontWeight.bold,
            color: _selectedCountryName == countryName ? Colors.white : Colors.black,
          ),
          textAlign: TextAlign.center,
        ),
      ),
    );
  }).toList(),
),
Enter fullscreen mode Exit fullscreen mode

D. Responsive Logo Example

ClipOval(
  child: Image.asset(
    'assets/icon/logo5.jpg',
    height: screenHeight * 0.12,
    width: screenHeight * 0.12,
    fit: BoxFit.cover,
  ),
),
Enter fullscreen mode Exit fullscreen mode
  1. Advanced: Responsive Layouts with LayoutBuilder and Breakpoints For more complex screens, use LayoutBuilder to change layouts based on available width:
LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 600) {
      // Mobile layout
      return Column(...);
    } else {
      // Tablet/Desktop layout
      return Row(...);
    }
  },
)
Enter fullscreen mode Exit fullscreen mode

Tip: Use breakpoints (e.g., 600px for mobile/tablet) to switch layouts.

  1. Best Practices Checklist Wrap main content in SafeArea.

Wrap long content in SingleChildScrollView.

Use MediaQuery for all sizes and font sizes.

Avoid hardcoded pixel values.

Test on multiple screen sizes and orientations.

Use Expanded and Flexible for dynamic layouts.

Use FractionallySizedBox or double.infinity for fluid widths.

  1. Example: Full Responsive Country Selection Page
@override
Widget build(BuildContext context) {
  double screenWidth = MediaQuery.of(context).size.width;
  double screenHeight = MediaQuery.of(context).size.height;
  double buttonWidth = screenWidth * 0.8;
  if (buttonWidth < 180) buttonWidth = 180;
  if (buttonWidth > 350) buttonWidth = 350;

  return Scaffold(
    appBar: AppBar(title: const Text("Select Country")),
    body: SafeArea(
      child: SingleChildScrollView(
        child: Center(
          child: Column(
            children: [
              SizedBox(height: screenHeight * 0.03),
              ClipOval(
                child: Image.asset(
                  'assets/icon/logo5.jpg',
                  height: screenHeight * 0.12,
                  width: screenHeight * 0.12,
                  fit: BoxFit.cover,
                ),
              ),
              SizedBox(height: screenHeight * 0.03),
              Column(
                children: countryData.keys.map((countryName) {
                  return GestureDetector(
                    onTap: () => _onCountrySelected(countryName),
                    child: Container(
                      width: buttonWidth,
                      padding: EdgeInsets.symmetric(
                        vertical: screenHeight * 0.015,
                        horizontal: 20,
                      ),
                      margin: EdgeInsets.symmetric(
                        vertical: screenHeight * 0.008,
                      ),
                      decoration: BoxDecoration(
                        color: Color(int.parse(countryData[countryName]!['color']!)),
                        borderRadius: BorderRadius.circular(10),
                        border: Border.all(
                          color: _selectedCountryName == countryName ? Colors.white : Colors.grey,
                        ),
                      ),
                      child: Text(
                        countryName,
                        style: TextStyle(
                          fontSize: screenWidth * 0.045,
                          fontWeight: FontWeight.bold,
                          color: _selectedCountryName == countryName ? Colors.white : Colors.black,
                        ),
                        textAlign: TextAlign.center,
                      ),
                    ),
                  );
                }).toList(),
              ),
              SizedBox(height: screenHeight * 0.03),
              Padding(
                padding: EdgeInsets.symmetric(horizontal: screenWidth * 0.05),
                child: Text(
                  _selectedCountryName.isNotEmpty
                      ? 'Selected Country: $_selectedCountryName'
                      : 'No country selected',
                  style: TextStyle(
                    fontSize: screenWidth * 0.04,
                    fontWeight: FontWeight.w500,
                  ),
                  textAlign: TextAlign.center,
                ),
              ),
              SizedBox(height: screenHeight * 0.02),
            ],
          ),
        ),
      ),
    ),
  );
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)