LoginSignup
16
3

More than 1 year has passed since last update.

Flutter Webでレスポンシブ対応する

Last updated at Posted at 2023-01-01

はじめに

Flutter for Webでは、通常のCSSやSassと比較した場合レスポンシブ対応が難しい印象を持ちます。
昨今はAndroid系列の端末をはじめ、様々な画面サイズが登場しているためFlutter WebのOverflowエラーが発生しやすい原因となっています。

この記事では、2パターンのレスポンシブ対応について解説したいと思います。
手法自体は通常のWebと同じですが、画面幅を取得し、画面ごとPC用、Tablet用、Mobile用を用意して切り替えるケースと、画面幅に応じてスタイルを切り替えるケースです。

ケース1:画面ごと切り替える

こちらの手法の場合、responsive_builderというパッケージがとても便利です

使い方

import 'package:flutter/material.dart';
import 'package:responsive_builder/responsive_builder.dart';

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

  @override
  Widget build(BuildContext context) {
    return ScreenTypeLayout(
      mobile: const SampleMobilePage(),
      tablet: const SampleTabletPage(),
      desktop: const SampleDesktopPage(),
    );
  }
}

また、私の所感的にデフォルトのブレイクポイントでも問題ありませんが、ブレイクポイントもカスタム可能です。
しかし、watchのブレイクポイントもrequiredのため指定しないといけない上、mobileは指定できないので注意が必要です。

import 'package:flutter/material.dart';
import 'package:responsive_builder/responsive_builder.dart';

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

  @override
  Widget build(BuildContext context) {
    return ScreenTypeLayout(
      breakpoints: ScreenBreakpoints(
        tablet: 600,
        desktop: 950,
        watch: 300,
      ),
      mobile: const SampleMobilePage(),
      tablet: const SampleTabletPage(),
      desktop: const SampleDesktopPage(),
    );
  }
}

ケース2:スタイル側で切り替える

やることは同じです。
こちらでブレイクポイントを指定し、それぞれ切り替えるだけです。
以下のようなenumとメソッドを用意してみました。

なお、ブレイクポイントはこちらのサイトを参考に設定しました!

device_type.dart
import 'package:flutter/material.dart';

/// デバイスの種類を判定する
enum DeviceType {
  mobile,
  tablet,
  desktop,
}

DeviceType getDeviceType(BuildContext context) {
  final screenWidth = MediaQuery.of(context).size.width;
  if (screenWidth < 430) {
    return DeviceType.mobile;
  } else if (screenWidth < 1024) {
    return DeviceType.tablet;
  } else {
    return DeviceType.desktop;
  }
}

使い方

sample_page.dart
class SamplePage extends StatelessWidget {
  const SamplePage({super.key});

  /// デバイス種別に応じてwidthを変更する
  double getDialogWidth(BuildContext context) {
    final screenWidth = MediaQuery.of(context).size.width;
    final deviceType = getDeviceType(context);
    switch (deviceType) {
      case DeviceType.mobile:
        return screenWidth * 0.75;
      case DeviceType.tablet:
        return screenWidth * 0.56;
      case DeviceType.desktop:
        return screenWidth * 0.36;
    }
  }

  double getDialogHight(BuildContext context) {
    final screenWidth = MediaQuery.of(context).size.width;
    final screenHeight = MediaQuery.of(context).size.height;
    final deviceType = getDeviceType(context);
    switch (deviceType) {
      case DeviceType.mobile:
        return screenWidth * 0.85;
      case DeviceType.tablet:
        return screenWidth * 0.68;
      case DeviceType.desktop:
        return screenHeight * 0.64;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Dialog(
      child: SizedBox(
        height: getDialogHight(context),
        width: getDialogWidth(context),
      ),
    );
  }
}

しかし、上記の例だとViewファイルが肥大化してしまいます。
そのため、sample_page_style.dartのようなファイルを別途設けることで
肥大化は避けられると思います。

16
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
3