【Flutter】レスポンシブ対応、画面崩れを防ぐためのTips・実装方法

## はじめに
Flutterでのレスポンシブ対応、画面崩れの防止についてどう実装するか、どんなパッケージを使うかなど、自分を含め、迷うと思います。
個人開発を通して、自分なりの現時点でのベストプラクティスを考えましたんで共有します。

# 告知
この記事に書いてある方法でレスポンシブ対応も行いました、
`タスクカレンダー`というアプリをリリースしました！
（まだ改善の余地がたくさんありますが、、）
*記事を書いた今日は僕の誕生日なので、プレゼントにぜひアプリをインストールしてあげてください！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2567243/6f68b123-0d4f-4a9d-b128-c68608c7d625.png" width="550">

コンセプトは、めちゃめちゃ手軽なカレンダー兼タスク管理アプリです。
普段は、めんどくさくてカレンダーアプリを使わないが、たまにある美容室の予定は忘れられない時など、ちょっとしたことを最低限の機能でストレスなく行えます。

ぜひ一度、アプリを手に取ってみてください！！！

ダウンロードは下から可能です。

<a href='https://play.google.com/store/apps/details?id=com.app.taskManagement&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Google Play で手に入れよう' src='https://play.google.com/intl/ja/badges/static/images/badges/ja_badge_web_generic.png' width="220" height="120"/></a>　　　　<a href="https://apple.co/3HcoulN"><img src="https://tools.applemediaservices.com/api/badges/download-on-the-app-store/black/ja-jp?size=250x83&amp;releaseDate=1659139200&h=0e6cd676b88181534f9150591ccc8dcd" alt="Download on the App Store" width="210"></a>

## MediaQuery.of(context).sizeを使う
1番一般的な方法だと思います。
デバイスの画面サイズを取得して、その値を使って、サイズを指定する方法です。

例えば、画面の幅は次のように取得できます。
```dart
double deviceWidth = MediaQuery.of(context).size.width; //画面の横幅を取得

Container(width: deviceWidth * 0.8),
```
この取得した値を使って、このように条件分岐のブレイクポイントとしても使え、UIを変更することもできます。たとえば、画面の幅が500px以下の場合には、サイドバーを非表示にするような処理を書くことができます。
```dart
if (deviceWidth <= 500) {
  return Scaffold(
    body: Center(
      child: Text('この画面ではサイドバーは表示されません'),
    ),
  );
} else {
  return Scaffold(
    drawer: SideBar(),
    body: Center(
      child: Text('サイドバーが表示されます'),
    ),
  );
}
```
ただし、`MediaQuery.of(context)`を使うと、コンパイル時に値が決定されないため、constをつけることができません。このため、パフォーマンスが悪くなる可能性があります。そのため、`MediaQuery.of(context)`を多用しすぎることは避けるべきだと考えます。
全てのサイズを画面サイズのxx倍とかで指定するより、
必要なところで、ブレイクポイントとして使うのが良いかと思います。

## MediaQuery.of(context).textScaleFactorを使う
端末のテキストサイズで設定されているフォントの倍率値のことです。 Flutterのアプリでは`TextScaleFactor`を用いて、論理ピクセルでのフォントサイズが決定されます。

わかりやすくいうと、例えばiPhoneやAndroid端末の設定で「文字サイズを大きくする」などの設定の際にアプリ内の文字の大きさ（倍率）が変わってしまいます。
ユーザーがスマホの文字の大きさを変更してもUIが崩れない必要があります。
そこでこちらを使ってUIの崩れをなくすことができます。

`スマホの「文字を大きくする」設定をしていても、UIが崩れないような画面設計が重要`ですが、
画面に情報量が多かったり、スクロールできなくて、大きさが限定されている時などは、「文字を大きくする」設定を無視したり、倍率の上限を設けたりする対策が可能です。


特定のテキストウィジェットで端末設定を無視（文字サイズを固定）
```dart
Text(
   "単体のテキストウィジェットの文字サイズ固定",
   style: TextStyle(fontSize: 24),
   textScaleFactor: 1.0,
);
```

アプリケーション全体でで端末設定を無視（文字サイズを固定）
```dart
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, child) {
        return MediaQuery(
          data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),//固定
          child: child!,
        );
      },
      title: 'Flutter Project',
      home: const HomePage(),
    );
  }
}
```
詳しくはこちらをご覧ください。
[Flutterで端末の文字サイズ設定を無視する方法](https://zenn.dev/ktakayama/articles/1b741f765b4f24)

textScaleFactorについて実践的で役に立つ面白い記事があったので共有しておきます。
[WINTICKET Flutter アプリと Text Scale Factor の闘い](https://developers.cyberagent.co.jp/blog/archives/36310/)

## device_previewを使う
ここからは、プログラミングではなく、開発の役に立つツールなどです。
[パッケージのリンクはこちら](https://pub.dev/packages/device_preview)
![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2567243/549adacb-682f-5c95-ac9a-cfe936518c54.gif)
`device_preview`を使うと、一回のビルドでたくさんの画面サイズ、文字サイズ、テーマなどを確認することができるので、いちいちシュミレータをセットアップしてビルドする手間が省けてとても便利です。

ただ、公式のREADMEにも記載されているのですが、`device_preview` は全てのデバイスの動きを完全に再現できる訳ではないというところは注意が必要です。
ですので、最終の動作、UIのテストは実際のそれぞれのシュミレーター、エミュレータ、で行うか、実機で行うようにした方が良いです。

他の方が解説していただいている詳しい導入の仕方などは[こちら](https://zenn.dev/mamushi/articles/flutter_device_preview)から！

## iPhoneの画面サイズを確認する
自分はiPhone、iPadのサイズを基準にしてレスポンシブを行いました。
以下の記事にiPhone,Ipadの画面サイズの一覧が記載されているので参考にしてください！
https://qiita.com/tomohisaota/items/f8857d01f328e34fb551

## おわり、その他
その他ですが、FlutterのUIを作る際に、できるだけ数値を指定せずにUIを作れるなら作った方が良いと思います。
Expandedや、ColumnのspaceBetweenなど、を使いながら、UIを作ると直接数値を指定するよりも、想定外のUI崩れが減ると思います！

以上が、Flutterでのレスポンシブデザインの実装、UI崩れの防止についてのTipsです。
一つでも参考になれば幸いです！いいねください！