【Flutter】MediaQuery実例集:初心者から上級者へ

対象者

  • MediaQueryを学びたい初心者の開発者
  • レスポンシブデザインに興味があるエンジニア
  • 効率的なアプリ開発を目指すITエンジニア

はじめに

この記事では、MediaQueryを使ってデバイスごとのレイアウトやデザインの最適化を実現する方法をわかりやすく解説しています。MediaQueryの基本的な使い方から、応用例、最適化方法まで、幅広くカバーしていますので、初心者から上級者まで幅広く対応しています。

アプリ開発の現場では、さまざまなデバイスに対応したレイアウトやデザインが求められますが、その方法が分からず悩んでいる方も多いのではないでしょうか?この記事を読むことで、そんな悩みを解決し、効率的な開発ができるようになります。

MediaQueryの基本

MediaQueryとは

MediaQueryは、Flutterアプリケーションでデバイスの現在のメディア(アプリを含むウィンドウ)のサイズや向きなどを取得・制御するために使用されるウィジェットです。これにより、異なる画面サイズやユーザーがフォントサイズやアニメーションをカスタマイズする場合に、より良いユーザーエクスペリエンスを提供するための異なるUIレイアウトを管理できます。

MediaQueryの利用方法

MediaQueryの利用方法はシンプルで、BuildContextを引数にMediaQuery.of関数を使用します。例えば、現在のウィンドウのサイズを取得するには、MediaQuery.of(context).sizeを使用します。これにより、画面の幅や高さを取得することができます。

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

MediaQueryDataのプロパティ

MediaQueryDataは、MediaQuery.of関数によって返されるデータで、さまざまなプロパティを提供しています。以下は、いくつかの主要なプロパティの例です。

  • size
    ウィンドウのサイズ(幅と高さ)を表すSizeオブジェクトを返します。
  • devicePixelRatio
    論理ピクセルと物理ピクセルの比率を返します。これにより、デバイスの実際の物理的な寸法を計算できます。
  • orientation
    ウィンドウの現在の向き(ポートレートまたはランドスケープ)を返します。
  • padding
    ウィンドウの各辺に適用されるパディングを返します。これにより、ステータスバーやノッチなどのシステムUI要素に対応できます。

これらのプロパティを使用して、アプリのUIをデバイスの様々な条件に適応させることができます。

MediaQueryを使った実例

画面サイズに応じたレイアウト調整

画面サイズが異なるデバイスで、アプリケーションのレイアウトが適切に表示されるようにするには、MediaQueryが役立ちます。特に、MediaQueryDataのsizeプロパティを利用することで、画面の幅と高さを取得できます。

例えば、以下のコードは、端末の幅に応じて異なるウィジェットを表示します。

Widget build(BuildContext context) {
  var screenWidth = MediaQuery.of(context).size.width;
  
  return screenWidth < 600 ? Container(color: Colors.red) : Container(color: Colors.blue);
}

上記のコードでは、画面の幅が600px未満の場合、赤色のコンテナを表示し、それ以上の場合は青色のコンテナを表示します。

デバイスの向きに応じたUIの変更

また、MediaQueryは端末の向きを検出するためにも使用できます。これにより、ポートレートモードとランドスケープモードで異なるレイアウトを表示することが可能になります。

以下に示すコードは、デバイスの向きに応じて異なるテキストを表示する例です。

Copy code
Widget build(BuildContext context) {
  var orientation = MediaQuery.of(context).orientation;
  
  return Text(
    orientation == Orientation.portrait ? 'Portrait mode' : 'Landscape mode'
  );
}

このコードは、端末が縦向き(ポートレートモード)の場合は’Portrait mode’と表示し、横向き(ランドスケープモード)の場合は’Landscape mode’と表示します。

このように、MediaQueryを利用することで、ユーザー体験を向上させることが可能です。デバイスの画面サイズや向きに柔軟に対応したアプリケーションを設計する際に、ぜひ活用してみてください。

MediaQueryの応用

カスタムフォントサイズの適用

MediaQueryを使用して、ユーザーのデバイス上でフォントサイズをカスタマイズすることができます。これにより、ユーザーが視認性の高いフォントサイズを選択できるようになります。以下は、MediaQueryを使用してカスタムフォントサイズを適用する方法の例です。

double customFontSize = MediaQuery.of(context).textScaleFactor * 16.0;
Text('Sample Text', style: TextStyle(fontSize: customFontSize));

この例では、デバイスのテキストスケールファクターを使用して、基本フォントサイズ(16.0)に倍率をかけることで、カスタムフォントサイズを計算しています。このフォントサイズは、TextウィジェットのTextStyleに適用されます。

MediaQuery.of(context).textScaleFactorについて

現在のデバイスでテキストをスケーリングするために使用されるファクター(倍率)を返すプロパティです。
この値は、ユーザーがデバイスの設定で設定した「テキストの大きさ」(または「フォントサイズ」)に基づいています。ユーザーはこの設定を調整して、システム全体のテキストの大きさを変更できます。例えば、視力に問題があるユーザーや高齢者は、通常よりも大きなテキストを好むかもしれません。逆に、情報を多く表示したいユーザーは、小さなテキストを好むかもしれません。
Flutterアプリケーションは、この設定をMediaQuery.of(context).textScaleFactorを通じて読み取り、テキストのスケーリングを調整します。これにより、各ユーザーの好みやニーズに適したテキストの大きさでアプリケーションを表示することができます。
なお、特定のテキストウィジェットでこのシステム設定を無視したい場合は、TextウィジェットのtextScaleFactorプロパティを直接設定することができます。

アニメーションの制御

MediaQueryは、アニメーションの制御にも使用できます。デバイスのモーション設定を参照して、アニメーションの速度や挙動をユーザーの好みに合わせて調整することができます。以下は、MediaQueryを使用してアニメーションの速度を制御する方法の例です。

AnimationController controller = AnimationController(
  duration: Duration(milliseconds: MediaQuery.of(context).disableAnimations ? 0 : 300),
  vsync: this,
);

controller.forward();

この例では、MediaQueryのdisableAnimationsプロパティを使用して、アニメーションが無効化されているかどうかをチェックしています。無効化されている場合は、アニメーションのデュレーションを0ミリ秒に設定し、そうでない場合は300ミリ秒に設定します。これにより、ユーザーのアニメーション設定に基づいてアニメーションの速度を制御できます。

MediaQuery.of(context).disableAnimations

ユーザーがアプリのアニメーションを無効にするかどうかを示します。これはMediaQueryDataクラスのプロパティで、システムレベルの設定に基づいています。アニメーションを有効または無効にするためには、ユーザーはデバイスの設定を変更する必要があります。

Android端末やiPhoneでの設定方法は以下の通りです:

  • Android:
    「設定」アプリを開きます。
    「ユーザ補助」をタップします。
    「色と動き」をタップします。
    「動きの低減」をオンまたはオフにします。

  • iPhone:
    「設定」アプリを開きます。
    「アクセシビリティ」をタップします。
    「動作」をタップします。
    「視差効果を減らす」をオンまたはオフにします。

MediaQueryの最適化

不要なリビルドを防ぐ方法

MediaQueryを用いてUIを調整する際、効率的なリビルドの方法に気を付けることが重要です。不要なリビルドを防ぐことで、アプリのパフォーマンスを向上させることができます。以下に、不要なリビルドを防ぐためのポイントを示します。

ー MediaQueryを必要な範囲でのみ使用する。

  • より具体的なMediaQueryを利用して、効率的なリビルドを実現する。

以下は、MediaQueryを必要な範囲でのみ使用する例です。

Column(
  children: [
    MediaQuery(
      data: MediaQuery.of(context).copyWith(textScaleFactor: 1.5),
      child: Text('Large text'),
    ),
    Text('Normal text'),
  ],
)

この例では、最初のTextウィジェットのみに大きなフォントサイズが適用されています。そのため、MediaQueryが変更された際、最初のTextウィジェットのみがリビルドされます。

initState内でのMediaQueryの使用

MediaQueryの情報は、通常、ビルドメソッド内で取得されます。ただし、一部のケースでは、初期化時にMediaQueryの情報が必要になることがあります。その際は、initStateメソッド内でMediaQueryを使用することができます。

以下は、initState内でMediaQueryを使用する例です。

class _MyAppState extends State<MyApp> {
  bool isLargeScreen = false;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() {
        isLargeScreen = MediaQuery.of(context).size.width > 600;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: isLargeScreen ? LargeScreenHomePage() : SmallScreenHomePage(),
    );
  }
}

この例では、initStateメソッド内でWidgetsBinding.instance.addPostFrameCallbackを使用して、フレーム描画後にMediaQueryの情報を取得しています。これにより、初期化時にデバイスの画面サイズに基づいて、適切なホームページを表示することができます。ただし、この方法はあまり一般的ではないため、通常のビルドメソッド内でMediaQueryを使用する方法を優先的に検討してください。

Q&A

Q1: MediaQueryの基本的な使い方はどのようなものですか?

A1: MediaQueryは、デバイスの画面サイズや向き、リフレッシュレートなどの情報に基づいてアプリケーションのレイアウトやデザインを調整するためのツールです。MediaQueryを利用することで、多様なデバイスに対応した最適なUIを提供することができます。

Q2: MediaQueryの応用例は何がありますか?

A2: MediaQueryの応用例として、カスタムフォントサイズの適用やアニメーションの制御などがあります。これらを使うことで、さらに高度なUIデザインやアニメーションを実現することができます。

Q3: MediaQueryを最適化する方法は何がありますか?

A3: MediaQueryの最適化方法として、不要なリビルドを防ぐ方法や、initState内でのMediaQueryの使用などがあります。これらを実践することで、アプリケーションのパフォーマンスを向上させることができます。

まとめ

この記事を通じて、私たちはMediaQueryの重要性とその活用方法を学びました。MediaQueryはFlutterで非常に有用なウィジェットであり、様々なデバイスや画面サイズに対応したUIを作成するのに役立ちます。画面の幅や高さを取得することで、レイアウトを調整することが可能です。さらに、デバイスの向き(ポートレートまたはランドスケープ)に基づいてUIを変更することもできます。

また、カスタムフォントサイズの適用やアニメーションの制御など、より細かいUIの調整にもMediaQueryは有用です。そして、最適化により不要なリビルドを防ぐ方法や、initState内でのMediaQueryの使用方法も学びました。

参考

ソース(main.dartにコピペして動作確認用)

以下に、MediaQueryを活用したFlutterのサンプルコードを示します。このコードでは、画面サイズに応じたレイアウト調整、デバイスの向きに応じたUIの変更、カスタムフォントサイズの適用、およびアニメーション制御が組み込まれています。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('MediaQuery Demo')),
        body: MediaQueryExample(),
      ),
    );
  }
}

class MediaQueryExample extends StatefulWidget {
  @override
  _MediaQueryExampleState createState() => _MediaQueryExampleState();
}

class _MediaQueryExampleState extends State<MediaQueryExample> {
  var _opacity1 = true;

  @override
  Widget build(BuildContext context) {
    var screenSize = MediaQuery.of(context).size;
    var textScaleFactor = MediaQuery.of(context).textScaleFactor;
    var orientation = MediaQuery.of(context).orientation;

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          'Screen Size: $screenSize',
          style: TextStyle(fontSize: 24),
        ),
        SizedBox(height: 10),
        Text(
          'Text Scale Factor: $textScaleFactor',
          style: TextStyle(fontSize: 24),
        ),
        SizedBox(height: 10),
        Text(
          'Orientation: $orientation',
          style: TextStyle(fontSize: 24),
        ),
        SizedBox(height: 20),
        if (orientation == Orientation.portrait)
          FilledButton(
            onPressed: () {},
            child: Text('Button for Portrait Mode'),
          )
        else
          FilledButton(
            onPressed: () {},
            child: Text('Button for Landscape Mode'),
          ),
        SizedBox(height: 20),
        FilledButton(
          onPressed: () {},
          child: Text(
            'Custom Font Size Button',
            style: TextStyle(fontSize: 16 * textScaleFactor),
          ),
        ),
        MediaQuery(
          data: MediaQuery.of(context).copyWith(textScaleFactor: 1.5),
          child: Text('Large text'),
        ),
        FilledButton(
          onPressed: () {
            setState(() {
              _opacity1 = !_opacity1;
            });
          },
          child: AnimatedOpacity(
            duration: Duration(
                seconds: MediaQuery.of(context).disableAnimations ? 0 : 1),
            opacity: _opacity1 ? 1 : 0.3,
            child: Text('AnimatedOpacity'),
          ),
        ),
      ],
    );
  }
}

このサンプルコードは、MediaQueryを使用してスクリーンサイズ、テキストスケールファクター、およびデバイスの向きを取得して表示しています。また、向きに応じてボタンのテキストを変更し、カスタムフォントサイズを適用したボタンも実装しています。このサンプルコードを参考に、MediaQueryを利用したアプリ開発に取り組んでみてください。