【Flutter】flutter_screenutilを使ってデザイン時から複数のアスペクト比に対応する画面設計

flutter_screenutilについて

pub.dev

スクリーンサイズが異なる端末でも、Widgetのサイズの比率を一定に保って表示してくれるパッケージです。

例えば下図のような2つのスクリーンサイズが異なる端末があるとします。

iPhone14上で、横を211(スクリーン横の1/3)、縦を130(スクリーン縦の1/4)となるようにContainerウィジェットを定義します。

//省略
ScreenUtilInit(
      designSize: const Size(390, 844),
      ....
//省略

Container(
  width: 130.w,
  height: 211.h,
  child:......
)

//省略

すると、アプリをiPhone SE 2022で起動した場合、Containerウィジェットのサイズが、スクリーンサイズに対して同じ比率になるようにflutter_screenutilが自動計算してくれます。

詳しい使い方は、解説しているサイトがいっぱいあるので調べてみてください。


アスペクト比が異なる画面でのレイアウト崩れ

デザイン時と異なるアスペクト比の端末でアプリを開いた際に、レイアウト崩れが発生します。特に、画像データなどの縦横比があらかじめ決まっているものを用いる場合が問題となります。

例として、下図の390x844(9:19.5)の画面サイズでデザインしたものが、画面サイズによってどのようにかわってくるのか確認してみましょう。

左が390x844(9:19.5)の画面のスクリーンショットです。こちらはデザインどおりに出力されています。 一方で、右は375x667(9:16)の画面で表示した場合ですか、明らかにレイアウトが崩れてしまっています。

  1. タイトルの背景画像が大きくなりすぎてしまっています。
  2. リストの各要素間の余白が無くなってしまっています。
  3. フレームに対して文字のサイズが小さくなってしまっています。

こういったレイアウトのズレを発生させないようにするにはどうすればよいかを考えていきたいと思います。


デザイン時に複数のアスペクト比を考慮にいれる

上記の問題を解決するため、「横方向の画面サイズの変化に対して、ウィジェットが影響をうけないようにする」というデザインの方針で進めます。

先ほどは9:19.5のアスペクト比のみを考慮してデザインを作成していましたが、使用される可能性のある複数の画面サイズを考慮してデザインを作成します。

とりあえず、世の中で最もよく使われる画面サイズを9:19.5、横長のものをを9:16、縦長のものを9:21としてデザインを作成します。

それらの高さを合わせて重ね、下図のような画面の枠を作成します。 こちらの枠をベースに進めます。

そして、その結果がこちらです。

いくつかポイントを確認しましょう。

①画面両端まで表示したい画像は最も横長の画面にあわせる

タイトルの背景画像を9:16の横幅に合わせます。幅の小さい画面の場合は、画像サイズを変えるのではなく、表示範囲を狭めることで調整できるようにします。

②Containerウィジェットの横幅を縦幅の比率ベースで決める

○○.wと書きたくなるころですが、そうすると、画面の横幅の変化の影響を受けてしまいますので、Containerウィジェットの縦幅265.hに対して、画像の縦横比を用いて265.h*200/147と計算します。

③縦に細長い画面のために画面両端にパディングをとる

細長い画面で表示すると、両端が隠されて見えなくなってしまいます。そこで、画面横幅の差に応じてパディングを設定します。今回は計算の結果14.5を確保していれば大丈夫でした。

④ScreenUtilの設定を変更する

下記のように設定を変更しましょう。

 /*省略*/

const designSize = Size(390, 844);

 /*省略*/

ScreenUtilInit(
  designSize: designSize ,
  minTextAdapt: true,
  scaleByHeight: MediaQuery.of(context).size.aspectRatio < designSize.aspectRatio,
  builder: (context, child) => /*省略*/
);

 /*省略*/


改善されたレイアウト

こんなかんじになります。