🏗️

【Flutter】画面サイズや向きに対して最適なレイアウトを構築できるUIパッケージを作った

2023/05/19に公開

こんにちは。広瀬マサルです。

マルチプラットフォームかつ単一コードでアプリ開発が可能なFlutterの特徴を活かし、単一コードで複数のプラットフォームの見た目を調整できるパッケージを作りました。

使い方をまとめたので興味ある方はぜひ使ってみてください!

masamune_universal_ui

https://pub.dev/packages/masamune_universal_ui

はじめに

Flutterは様々なプラットフォームに対応できる利点がある一方で、プラットフォームごとのUIの違いによって開発者が悩まされる欠点があります

Webやデスクトップ向けに開発する場合、タブレット向けのUIも考慮しなければならないため開発コストが上がってしまいます。

Flutterのウィジェットはプラットフォームに依存しないため、そのままではプラットフォーム固有のUIを実現できません。そのため、開発者はプラットフォームごとにUIをカスタマイズする必要があります。

Masamune Universal UIはレスポンシブデザインに対応し、ワンコードで様々なプラットフォーム上に対応可能なUIを生成するウィジェットを集めたフレームワークパッケージです。

Web、iOS、Android、デスクトップ向けに1つのコードで開発することができ、画面サイズに応じて表示が変化するため、開発者はそれぞれのプラットフォーム向けにUIをカスタマイズする必要がありません。

このパッケージを使用することで、プラットフォーム間でのUIの差を気にすることなく開発を進めることができます。

このパッケージはCSSのレイアウトフレームワークで有名なbootstrapをベースにしています。

横12個のグリッドレイアウトを指定でき、画面の横幅に応じて横並びから縦並びへと自然に画面レイアウトを再構築します。

インストール

下記パッケージをインポートします。

Masamuneフレームワークを利用している前提となるためMasamuneのパッケージも合わせてインポートしてください。

flutter pub add masamune_universal_ui
flutter pub add masamune

実装

事前準備

Masamuneフレームワークを利用している前提となります。

MasamuneApprunMasamuneAppmasamuneAdaptersUniversalMasamuneAdapterを渡して初期化してください。

void main() {
  runMasamuneApp(
    (adapters) => MasamuneApp(
      title: title,
      appRef: appRef,
      theme: theme,
      routerConfig: router,
      localize: l,
      authAdapter: authAdapter,
      modelAdapter: runtimeModelAdapter,
      storageAdapter: storageAdapter,
      functionsAdapter: functionsAdapter,
      masamuneAdapters: adapters,
    ),
    masamuneAdapters: [
      const UniversalMasamuneAdapter(),
    ],
  );
}

基本UI

基本的にはFlutterのUIを作る方法と変わりません。ScaffoldやAppBarなどの代わりにUniversalScaffoldUniversalAppBarなどのウィジェットを指定してUIを構築していきます。


Widget build(BuildContext context, PageRef ref) {
  return UniversalScaffold(
    appBar: UniversalAppBar(title: Text("Title"), backgroundColor: theme.color.secondary),
    body: UniversalColumn(
      crossAxisAlignment: CrossAxisAlignment.start,
      children:[
        Center(child: CircleAvatar(backgroundImage: theme.asset.userIcon.provider)),
        Text("User Name", style: theme.text.displayMedium)
      ]
    )
  );
}

UniversalScaffold

Scaffoldの代わりになるウィジェットです。通常のScaffoldに加えて下記の機能を利用可能です。

  • Header
    • bodyの上部にウィジェットを配置可能です。
  • Footer
    • bodyの下部にウィジェットを配置可能です。
  • Sidebar
    • bodyの左側にウィジェットを配置可能です。モバイル向けのUIの場合はbodyfooterの間に表示されます。
  • LoadingFuturesLoadingWidget
    • loadingFuturesにFuture(もしくはFutureOr)を与えるとFutureが終了するまでbody等を表示せずにインジケーターを表示します。
    • loadingWidgetを指定するとインジケーターを指定したものに変更可能です。
  • widthheightborderRadius
    • Scaffoldの画面全体をサイジングできます。
    • TransitionQuery.centerModalなどでページ遷移したときにモーダルのように利用することが可能です。

UniversalAppBar

AppBarの代わりになるウィジェットです。

titleactionの位置がPC向けとモバイル向けの場合で調整されます。

また通常のAppBarに加えて下記の機能を利用可能です。

  • subtitle
    • titleの下に小さく表示するサブタイトルです。

UniversalSliverAppBar

AppBarの代わりになるウィジェットです。UniversalScaffoldUniversalUIウィジェットを合わせて使うことで意識することなくSliver系のAppBarを利用できるようになります。

フィーチャー画像等をヘッダ部分に追加したい場合はこちらを利用してください。

そのままUniversalAppBarを入れ替えるだけで利用可能です。

UniversalContainer

UniversalScaffoldbody直下に置くことで効果を発揮するContainerウィジェットです。

Containerと同じように利用可能ですが、画面サイズに応じて自動でパディングが調整されます。

UniversalColumn

UniversalScaffoldbody直下に置くことで効果を発揮するColumnウィジェットです。

Columnと同じように利用可能ですが、画面サイズに応じて自動でパディングが調整されます。

またchildrenResponsiveのウィジェットを直下に置くことでグリッドデザインを作成することが可能です。(詳しくは下記をご参照ください)

UniversalListView

UniversalScaffoldbody直下に置くことで効果を発揮するListViewウィジェットです。

ListViewと同じように利用可能ですが、画面サイズに応じて自動でパディングが調整されます。

またchildrenResponsiveのウィジェットを直下に置くことでグリッドデザインを作成することが可能です。(詳しくは下記をご参照ください)

UniversalSliverAppBarを利用している場合は、内部でCustomScrollViewが利用されるので意識することなくSliver系のリストに変化します。

UniversalSideBar

UniversalScaffoldsideBar直下に置くことで効果を発揮するサイドバーウィジェットです。

画面サイズに応じて自動でパディングが調整されます。

グリッドデザイン

基本的な概念はbootstrapのページを参考にしてください。

https://getbootstrap.com/docs/5.3/layout/breakpoints/

このパッケージではUniversalColumnUniversalListViewResponsiveといった形でウィジェットを組んでいくことによりグリッドデザインを組み立てることができます。

Responsiveにてxssmmdlgxlxxl、の各ブレークポイントにて12個中のいくつに分割するかを指定することができます。

UniversalListView(
  children: [
    Responsive(
      lg: 12,
      child: Container(
        color: Colors.red,
        height: 100,
      ),
    ),
    Responsive(
      sm: 6,
      child: Container(
        color: Colors.green,
        height: 100,
      ),
    ),
    Responsive(
      sm: 6,
      child: Container(
        color: Colors.blue,
        height: 100,
      ),
    ),
  ],
);

おわりに

自分で使う用途で作ったものですが実装の思想的に合ってそうならぜひぜひ使ってみてください!

また、こちらにソースを公開しているのでissueやPullRequestをお待ちしてます!

また仕事の依頼等ございましたら、私のTwitterWebサイトで直接ご連絡をお願いいたします!

https://mathru.net/ja/contact

GitHub Sponsors

スポンサーを随時募集してます。ご支援お待ちしております!

https://github.com/sponsors/mathrunet

Discussion