Development

【Flutter】デバイスサイズに応じたレスポンシブ対応(flutter_screenutil)

1. はじめに

弊社で開発したスマートフォン・タブレット向けアプリの案件で、デバイスごとに異なる画面サイズや解像度への対応に悩まされる場面がありました。
具体的には、スマートフォンの機種によってレイアウトが崩れたり、タブレットで表示した際に画面が見づらくなったりするという問題が発生しました。
こうした課題に直面し、「flutter_screenutil」パッケージを活用してレスポンシブ対応を行いました。

本記事では、その具体的な対応方法について、簡単なサンプルコードとともにご紹介します。

2. スマートフォンの機種ごとのレスポンシブ対応

まずは、flutter_screenutilを使用してスマートフォンの機種ごとのレイアウト崩れを解消していきます。
flutter_screenutilはこのようなパッケージみたいです。(公式から抜粋)

画面とフォント サイズを適応させるための Flutter プラグイン。さまざまな画面サイズで UI が適切なレイアウトで表示されるようにします。https://pub.dev/packages/flutter_screenutil

まずは普通にレイアウトを作成

色のついたContainerを縦に3つ並べてみます。

body: Center(
  child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      Container(
        color: Colors.purple,
        height: 100,
        width: 200,
      ),
      Container(
        color: Colors.blue,
        height: 200,
        width: 200,
      ),
      Container(
        color: Colors.green,
        height: 300,
        width: 200,
      ),
    ],
  ),
),

iPhone 15とiPhone SEでビルドしてみます。

iPhone 15 iPhone SE

このように、iPhone 15では画面内に3つのContainerが全て収まっていますが、iPhone SEでは一番下のContainerが収まらず、オーバーフローしています。

ここで、flutter_screenutilを活用して、異なるサイズの端末でも同じように表示されるように対応していきます。

flutter_screenutilの活用

ターミナルからflutter_screenutilパッケージを入手。
今回使用したflutter_screenutilのバージョンは5.9.3です。

flutter pub add flutter_screenutil

flutter_screenutilを使用したいクラスにインポート。

import 'package:flutter_screenutil/flutter_screenutil.dart';

「ScreenUtilInit」の「designSize」に、基準となるサイズを設定します。
今回は、iPhone 15のサイズに合わせて、「横393px、縦852px」に設定しました。

void main() {
  runApp(ScreenUtilInit(
    designSize: const Size(393, 852),
    builder: (BuildContext context, Widget? widget) => const MyApp(),
  ));
}

Containerのサイズ指定に、横幅なら「.w」、縦幅なら「.h」をつけます。(「.w」などの意味は後述します。)

body: Center(
  child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      Container(
        color: Colors.purple,
        height: 100.h,
        width: 200.w,
      ),
      Container(
        color: Colors.blue,
        height: 200.h,
        width: 200.w,
      ),
      Container(
        color: Colors.green,
        height: 300.h,
        width: 200.w,
      ),
    ],
  ),
),

これでビルドすると、iPhone SEでのオーバーフローが解消され、iPhone 15と同じように、画面内に3つのContainerが収まるようになりました!

iPhone 15 iPhone SE
補足
.w」、「.h」とは?

「ScreenUtilInit」で設定した「designSize」の基準値に対し、現在のデバイスの画面の比率に基づいて計算される値です。
.w (width): widthは画面の横幅を基準にした相対値を指定します。
.h (height): heightは画面の縦幅を基準にした相対値を指定します。

3. スマートフォンとタブレットのレスポンシブ対応

ここまでで、スマートフォンの機種ごとのレイアウト崩れは解消できました。
しかし、タブレット端末でアプリを動かしてみると、画面項目のサイズが大きすぎたり小さすぎたり、操作感が悪くなってしまうことがありました。
そこで、スマートフォン端末の場合と、タブレット端末の場合で画面項目のサイズ指定を変えられるように、flutter_screenutilを活用していきます。

おおまかな流れとしては、flutter_screenutilを使用して端末のサイズを取得し、端末サイズの縦横比を計算することで、スマートフォン端末かタブレット端末かを判定し、サイズを指定します。

ボタンを作成

まずは、先と同じように、flutter_screenutilを導入し、ボタンを作成します。

body: Center(
  child: OutlinedButton(
    style: OutlinedButton.styleFrom(
      fixedSize: Size(200.w, 50.h),
      foregroundColor: Colors.white,
      backgroundColor: Colors.blue,
      shape: const StadiumBorder(),
      side: const BorderSide(color: Colors.black),
    ),
    onPressed: () {},
    child: const Text('Button'),
  ),
),

これを、iPhone 15とiPad Pro (12.9-inch)でビルドしてみます。

iPhone 15 iPad Pro (12.9-inch)

このように、タブレット端末では、ボタンがかなり横に長くなってしまいます。
配置したい場所のスペースが限られている場合などは、このボタンの横幅をもう少し短くしたい ということがあると思います。
ここで、flutter_screenutilを使用して、タブレット端末かどうかを判定し、サイズを調整します。

端末の縦横比に応じてサイズを調整

/// 正方形寄りの端末かどうかを判定する
/// 16:10までの比率の端末を正方形寄りと判定する
/// 1.61未満の場合に正方形寄りと判定する
bool isSquareDevice() {
  return ScreenUtil().screenHeight / ScreenUtil().screenWidth < 1.61;
}

「ScreenUtil().screenHeight」 で、画面の縦幅を取得し、「ScreenUtil().screenWidth」 で画面の横幅を取得します。
これらの比率を計算し、今回は、16:10までの比率の端末は「正方形寄り」と判定し、「タブレット端末である」と判定します。

 そして、この判定を用いて、ボタンの横幅のサイズ指定を切り替えます。

body: Center(
  child: OutlinedButton(
    style: OutlinedButton.styleFrom(
      fixedSize: Size(isSquareDevice() ? 100.0.w : 200.w, 50.h),
      foregroundColor: Colors.white,
      backgroundColor: Colors.blue,
      shape: const StadiumBorder(),
      side: const BorderSide(color: Colors.black),
    ),
    onPressed: () {},
    child: const Text('Button'),
  ),
),

「isSquareDevice() ? 100.0.w : 200.w」 では、正方形寄りの端末(タブレット端末)の場合、ボタンの横幅を「100.0.w」に設定し、それ以外の場合(スマートフォン端末)は、ボタンの横幅を「200.0.w」に指定します。

この状態でビルドすると、iPad Pro (12.9-inch)の場合のみ、ボタンの横幅を小さくすることができました!

iPhone 15 iPad Pro (12.9-inch)

また、「タブレット端末かどうか?」の判定に使用した16:10は、対応機種によって異なるかと思うので、タブレット判定したい機種がどれか によって変えると良いと思います。

4. おわりに

以上のように、flutter_screenutilを使用して、簡単にレスポンシブ対応を行うことができました。
これ以外にも方法はありそうなので、状況に合わせて使い分けると、さらに細かい対応が可能になりそうです。

レスポンシブ対応は、スマートフォンからタブレットまで幅広いデバイスを意識した開発では避けて通れない重要なポイントだと感じました。
本記事では、弊社の実際の開発案件を通じて直面した課題を解決するために取り組んだ、Flutterでのレスポンシブ対応についてご紹介しました!
この記事が同じような問題を抱える方の参考になれば幸いです。


Latest最新記事

Popular人気の記事