Building Responsive UI with MediaQuery and OrientationBuilder in Flutter

ยท

4 min read

Hello, fellow Flutter enthusiasts! ๐Ÿš€ I'm here to talk about something that will take your Flutter app development skills up a notch - building responsive user interfaces. Whether you're working on a smartphone or a tablet, ensuring your app looks great on any device is crucial. Today, we're diving into two powerful tools: MediaQuery and OrientationBuilder. Let's make our apps shine everywhere!

Unveiling the Power of MediaQuery

What's MediaQuery, Anyway?

Think of MediaQuery as your secret agent. It whispers important device details to you, helping you tailor your app to the user's environment. Let's unlock its potential step by step.

Accessing MediaQuery

To summon our trusty agent, we simply call MediaQuery.of(context). It provides us with a wealth of information about the device and screen.

final mediaQueryData = MediaQuery.of(context);

Discovering Screen Size

Want to know the dimensions of the screen your app is running on? MediaQuery is here to help:

final screenWidth = mediaQueryData.size.width;
final screenHeight = mediaQueryData.size.height;

Checking Orientation

Is the user holding their device in portrait or landscape mode? MediaQuery can give you the answer:

final isPortrait = mediaQueryData.orientation == Orientation.portrait;

Grasping Device Pixel Ratio

Pixel density matters, especially when dealing with images and text sizes. MediaQuery reveals the device's pixel ratio:

final pixelRatio = mediaQueryData.devicePixelRatio;

Embrace the Versatility of OrientationBuilder

OrientationBuilder: Your Layout Acrobat

Imagine your app's layout effortlessly flipping and rearranging itself as the user rotates their device. That's the magic of OrientationBuilder. Let's bring our UI to life with it!

Wrapping Your Widgets

To start using OrientationBuilder, wrap your widgets in it. This wizardry will provide you with the current orientation as a parameter:

OrientationBuilder(
  builder: (context, orientation) {
    // Your layout logic goes here.
  },
)

Adapting to Orientation Changes

Now, let's get practical. Here's how you can switch your UI elements based on the device's orientation:

OrientationBuilder(
  builder: (context, orientation) {
    if (orientation == Orientation.portrait) {
      // Show portrait UI.
    } else {
      // Show landscape UI.
    }
  },
)

Putting It All Together: Practical Examples

Let's bring our newfound knowledge to life with some real-world scenarios.

Scenario 1: A Weather App

Imagine you're developing a weather app. You want to display a five-day forecast on larger screens but switch to a simplified single-day view on smaller devices. Here's how you can do it:

if (mediaQueryData.size.width > 600) {
  return WideScreenLayout();
} else {
  return NarrowScreenLayout();
}

Scenario 2: A Reading App

Now, picture a reading app. In portrait mode, you want to focus on the text. However, in landscape mode, you'd like to display additional information alongside the text. OrientationBuilder makes it easy:

OrientationBuilder(
  builder: (context, orientation) {
    if (orientation == Orientation.portrait) {
      return TextReader();
    } else {
      return DetailedReadingLayout();
    }
  },
)

Share Your Responsive Creations

With MediaQuery and OrientationBuilder, crafting responsive Flutter apps is a breeze. You can create layouts that adapt seamlessly to any device or screen size. So go ahead, experiment, and create pixel-perfect, adaptable UIs!

Now that you're armed with these tools, it's time to share your responsive creations with the world. Let's make Flutter apps look fantastic on every device. Happy coding! ๐Ÿ“ฑ๐Ÿ’ปโœจ

Note: This blog post is inspired by personal experiences and Flutter's official documentation.


Full Code for Reference

Here's the full code to help you on your responsive journey:

main.dart:

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      //home: const Media(),
      home: const Oriten(),
    );
  }
}

media.dart:

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

class Media extends StatefulWidget {
  const Media({Key? key});

  @override
  State<Media> createState() => _MediaState();
}

class _MediaState extends State<Media> {
  @override
  Widget build(BuildContext context) {
    final mediaQueryData = MediaQuery.of(context);
    final screenWidth = mediaQueryData.size.width;
    final screenHeight = mediaQueryData.size.height;
    final isPortrait = mediaQueryData.orientation == Orientation.portrait;
    final pixelRatio = mediaQueryData.devicePixelRatio;

    return Scaffold(
      appBar: AppBar(
        title: const Text('Media'),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Text(
              "Hello, this is a text",
              style: GoogleFonts.rubikIso(
                fontSize: isPortrait ? 20 : 16,
                color: Colors.green[300],
              ),
            ),
            // Add your widgets here to try.
          ],
        ),
      ),
    );
  }
}

orientation.dart:

import 'package:flutter/material.dart';

class Oriten extends StatefulWidget {
  const Oriten({Key? key});

  @override
  State<Oriten> createState() => _OritenState();
}

class _OritenState extends State<Oriten> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Orientation'),
        centerTitle: true,
      ),
      body: OrientationBuilder(
        builder: (context, orientation) {
          if (orientation == Orientation.portrait) {
            return PortraitLayout();
          } else {
            return LandscapeLayout();
          }
        },
      ),
    );
  }
}

class PortraitLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          "Portrait Mode",
          style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
          ),
        ),
        SizedBox(
          height: 20,
        ),
        Icon(
          Icons.mobile_friendly,
          size: 100,
        ),
      ],
    );
  }
}

class LandscapeLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          "Landscape Mode",
          style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
          ),
        ),
        SizedBox(
          height: 20,
        ),
        Icon(
          Icons.laptop_windows,
          size: 100,
        ),
      ],
    );
  }
}

Remember to adjust and expand on this code according to your app's specific requirements.

Video: https://youtu.be/otmsUXamIOk (in Hindi)

ย