Flutterでレスポンシブデザインの実装例
Flutterによるレスポンシブデザインは、いくつかの実装方法はありますが、そのうちの1例をご紹介いたします。 この実装を行うことによって1つのソースコードでスクリーンサイズ幅に合わせ、スマートフォン、タブレット、デスクトップの3種で切り替わるようになります。
目次
実装バージョン
今回のサンプルバージョンは次のようになっています。
- Windows 10
- Android Studio Chipmunk | 2021.2 Patch 2
- Flutter 3.10.2
iOSでは試しておりませんが、問題なく動作するものと思われます。
このサンプルによるゴール
次のような結果を目指します。
ご注意
当記事はあくまでサンプルとして掲載しているものとなります。予めご了承ください。
ソース構成
簡単な解説
それでは各プログラムソースの説明をいたします。
まず適当なプロジェクトを作成します。プロジェクト作成については解説いたしません。今回は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を構成するとよいでしょう。
カラーは赤系にしました。
ビルドについて
まとめ
重要な点はresponsive_layout.dartで定義しているLayoutBuilderです。LayoutBuilderは動的に子ウィジェットを構築することができるウィジェットで、これでレスポンシブなレイアウトを提供しています。 また、幅によってAppBarのテキストを差し替えているため、タブレットの横幅などによっては「デスクトップ」と表示されます。今回はわかりやすくするためにしていますので、実際のアプリ開発ではこのようなテキストはおそらくないと思いますのでご了承ください。
今後、もうすこしレイアウトを凝ったコードも掲載できるようでしたらご紹介いたします。