技術情報・コラム記事
Flutter

Flutterでレスポンシブデザインの実装例

Flutterによるレスポンシブデザインは、いくつかの実装方法はありますが、そのうちの1例をご紹介いたします。 この実装を行うことによって1つのソースコードでスクリーンサイズ幅に合わせ、スマートフォン、タブレット、デスクトップの3種で切り替わるようになります。

目次

実装バージョン

今回のサンプルバージョンは次のようになっています。

  • Windows 10
  • Android Studio Chipmunk | 2021.2 Patch 2
  • Flutter 3.10.2

iOSでは試しておりませんが、問題なく動作するものと思われます。

このサンプルによるゴール

次のような結果を目指します。

flutter-ScreenSize-Image.gif

ご注意

当記事はあくまでサンプルとして掲載しているものとなります。予めご了承ください。

ソース構成

flutter-responsive-design-structure.png
上記のような構成にしていますが、プロジェクトに合わせて構成してください。

簡単な解説

それでは各プログラムソースの説明をいたします。

まず適当なプロジェクトを作成します。プロジェクト作成については解説いたしません。今回はflutter_3102_responsiveとしてプロジェクトを作成しています。また、必要なパッケージもありませんので、pubspec.yamlも編集しません。

main.dart


import 'package:flutter/material.dart';
import 'package:flutter_3102_responsive/homepage.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.white),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

main.dartは始まりのコードです。特に難しいことはしておりません。デフォルトコードを一通り削除し、上記のように定義します。赤い波線のエラーや警告が出るかもしれませんが、この時点では気にしないでおきます。 また、debugShowCheckedModeBannerをfalseにして、Debug帯を非表示にしています。

homepage.dart


import 'package:flutter/material.dart';
import 'package:flutter_3102_responsive/responsive_layout.dart';
import 'responsive/desktop_body.dart';
import 'responsive/tablet_body.dart';
import 'responsive/moble_body.dart';


class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State createState() => _HomePageState();
}

class _HomePageState extends State {
  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: ResponsiveLayout(
        mobileBody: MobileBody(),
        tabletBody: TabletBody(),
        desktopBody: DesktopBody(),
      ),
    );
  }
}

homepage.dartはmain.dartから呼び出されるHomePageウィジェットを定義しています。
ここではWindowサイズによって3つのウィジェットを実装するResponsiveLayoutウィジェットに渡し、スクリーン幅に合わせてレイアウトを返します。こちら作成の時点では、responsive_layout.dart、desktop_body.dart、tablet_body.dart、moble_body.dartなどのプログラムは作成しておりませんので、importをまだしておかないか、必要なファイルを空っぽでよいので作成してください。あるいは、存在していない状態でエラーや警告が出ても気にしない方はそのまま記載してください。

responsive_layout.dart


import 'package:flutter/material.dart';
import 'package:flutter_3102_responsive/const/layout.dart';

class ResponsiveLayout extends StatelessWidget {
  final Widget mobileBody;
  final Widget tabletBody;
  final Widget desktopBody;

  const ResponsiveLayout({
    Key? key,
    required this.mobileBody,
    required this.tabletBody,
    required this.desktopBody
  }): super(key: key);

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
        builder: (context, constraints) {
          if (constraints.maxWidth < mobileWidth) {
            return mobileBody;
          } else if (constraints.maxWidth < tabletWidth) {
            return tabletBody;
          } else {
            return desktopBody;
          }
        }
    );
  }
}

こちらのウィジェットがサイズ切替の本体となります。
homepage.dartより渡された各スクリーンに合わせたレイアウトを受け取り、LayoutBuilderよりスクリーンのサイズをアクティブに取得し返却するウィジェットを切り替えます。
ウィジェット幅についての定義は const/layout.dart に記述します。

const/layout.dart


// デバイス幅設定
const mobileWidth = 600;    //600pxまで
const tabletWidth = 1100;   //1100pxまで  (pcはそれ以上のサイズ)

特筆すべき内容はありません。スマートフォンは600px未満のサイズで、タブレットの場合は1100px未満のサイズ、デスクトップはそれ以上という定義を行います。もちろん、PCアプリやブラウザでスクリーンサイズを変えることにより幅で切り替わります。

  • 0~599pxまで モバイルサイズ
  • 600~1099pxまで タブレットサイズ
  • 1100px~以降 デスクトップサイズ

※これらのサイズは絶対ではありません。世の中にあるデバイスで大体このあたりだろうというサイズで設定しているため、アプリケーションや状況に合わせてサイズを決定してください。

responsive/moble_body.dart


import 'package:flutter/material.dart';

class MobileBody extends StatelessWidget {
  const MobileBody({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final currentWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: const Text('スマートフォン'),
        backgroundColor: Colors.green[200],
      ),
      body: Center(
        child: Text(currentWidth.toString()),
      ),
    );
  }
}

最初にスマートフォン用のレイアウトをここに定義します。

こちらでスマートフォンサイズに合ったレイアウトを記述しリスト型のレイアウト構成になると思います。
また、MediaQuery.of(context).size.widthにより現在の横幅を取得し、わかるようにTextにて表示させています。カラーは緑系にしました。

responsive/tablet_body.dart


import 'package:flutter/material.dart';

class TabletBody extends StatelessWidget {
  const TabletBody({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final currentWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: const Text('タブレット'),
        backgroundColor: Colors.blue[200],
      ),
      body: Center(
        child: Text(currentWidth.toString()),
      ),
    );
  }
}

次にタブレット用のレイアウトをここに定義します。

こちらでタブレットサイズに合ったレイアウトを記述しリストまたは、サイドメニューなどを表示させるレイアウト構成等になると思います。カラーを青系にしました。
同様に、MediaQuery.of(context).size.widthにより現在の横幅を取得し、わかるようにTextにて表示させています。

responsive/desktop_body.dart


import 'package:flutter/material.dart';

class DesktopBody extends StatelessWidget {
  const DesktopBody({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final currentWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: const Text('デスクトップ'),
        backgroundColor: Colors.red[200],
      ),
      body: Center(
        child: Text(currentWidth.toString()),
      ),
    );
  }
}

最後にデスクトップ用のレイアウトをここに定義します。

デスクトップ用は様々な機能を最初から見えるような形にするか、デスクトップに適した配置でUIを構成するとよいでしょう。
カラーは赤系にしました。

ビルドについて

個人の設定によりますが、Flutterの初期設定でAndroid,iOSの設定のほかにweb設定も含めておきましょう。Google Chromeなどでスクリーンサイズの確認ができます。

まとめ

重要な点はresponsive_layout.dartで定義しているLayoutBuilderです。LayoutBuilderは動的に子ウィジェットを構築することができるウィジェットで、これでレスポンシブなレイアウトを提供しています。 また、幅によってAppBarのテキストを差し替えているため、タブレットの横幅などによっては「デスクトップ」と表示されます。今回はわかりやすくするためにしていますので、実際のアプリ開発ではこのようなテキストはおそらくないと思いますのでご了承ください。

今後、もうすこしレイアウトを凝ったコードも掲載できるようでしたらご紹介いたします。

他にも企業の課題に合わせた様々なシステムを開発しています

ソリューション・開発事業について詳しく  
TOP技術情報・コラム記事Flutterでレスポンシブデザインの実装例