mcpField
F
flutter-build-responsive-layout

flutter-build-responsive-layout

github.com/flutterデザイン・UI3.1k43.1k 回インストール2 日前に更新
リポジトリ

flutter-build-responsive-layout について

デバイスの種類ではなく、アプリウィンドウの利用可能な空間に合わせる Flutter のアダプティブレイアウト設計スキルです。制約、大画面での幅調整、入力方法を扱います。

主な機能

  1. 01ウィンドウ空間に応じたレイアウト
  2. 02LayoutBuilder による幅判定
  3. 03大画面でのコンテンツ幅制限
  4. 04長いリストの遅延描画
  5. 05マウス、キーボード、タッチへの対応

活用シーン

  1. 01サイズ変更可能なウィンドウ向け UI 設計
  2. 02画面サイズに応じたレイアウト切り替え
  3. 03大画面でのコンテンツの横伸び防止
  4. 04大規模リストの描画最適化

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/flutter/agent-plugins --skill flutter-build-responsive-layout

インストール後、Claude Code で/flutter-build-responsive-layoutを入力して読み込まれたか確認します。

詳細

アダプティブレイアウトの実装

目次

スペースの測定に関するガイドライン

レイアウトが物理デバイスだけでなく、アプリウィンドウに合わせて調整されるよう、利用可能なスペースを正確に把握してください。

  • MediaQuery.sizeOf(context) を使用すると、アプリウィンドウ全体のサイズを取得できます。
  • LayoutBuilder を使用すると、親ウィジェットに割り当てられたスペースに基づいてレイアウトを決定できます。constraints.maxWidth を評価し、返すウィジェットツリーを決定してください。
  • ウィジェットツリーの上位では、レイアウト切り替えに MediaQuery.orientationOf や OrientationBuilder を使用しないでください。デバイスの向きは、利用可能なアプリウィンドウのスペースを正確に反映しません。
  • ハードウェアの種類(「スマートフォン」か「タブレット」かなど)を判定しないでください。Flutter アプリは、サイズ変更可能なウィンドウ、マルチウィンドウモード、ピクチャーインピクチャーで動作します。レイアウトの決定はすべて、利用可能なウィンドウのスペースだけに基づいて行ってください。

ウィジェットのサイズと制約

Flutter の基本的なレイアウトルールを理解し、適用してください。制約は下へ渡り、サイズは上へ伝わります。位置は親が設定します。

  • スペースを配分する: Row、Column、Flex ウィジェット内で Expanded と Flexible を使用します。
    • Expanded を使用すると、子ウィジェットを残りの利用可能なスペースいっぱいに広げられます(fit: FlexFit.tight および flex 係数が 1.0 の Flexible と同等です)。
    • Flexible を使用すると、子ウィジェットのサイズを指定した上限まで許容しながら、拡大・縮小できます。兄弟ウィジェット間でスペースを消費する比率は、flex 係数で指定します。
  • 幅を制限する: 大画面でウィジェットが水平方向のスペースをすべて占有しないようにします。GridView や ListView などのウィジェットを ConstrainedBox または Container でラップし、BoxConstraints で maxWidth を指定してください。
  • 遅延レンダリング: アイテム数が不明または多いリストをレンダリングする場合は、必ず ListView.builder または GridView.builder を使用してください。

デバイスと向きの動作

あらゆるデバイスのフォームファクターや入力方法で、アプリが正しく動作するようにしてください。

  • 画面の向きを固定しないでください。 向きを固定すると、折りたたみ式デバイスで深刻なレイアウトの問題が発生し、黒い枠で囲まれたアプリが中央に表示されるレターボックス表示になることがよくあります。Android の大画面デバイスでは、縦向きと横向きの両方への対応が必要です。
  • 向きを固定する場合の代替策: 業務要件で向きの固定が厳密に必須の場合は、MediaQuery ではなく Display API を使用して物理画面の寸法を取得してください。互換モードでは、MediaQuery はより大きなウィンドウサイズを取得できません。
  • 複数の入力方法に対応する: 基本的なマウス、トラックパッド、キーボードショートカットに対応してください。タッチターゲットを適切なサイズにし、キーボード操作にも対応してください。

ワークフロー:アダプティブレイアウトの構築

このワークフローに沿って、利用可能な BoxConstraints に合わせて調整されるレイアウトを実装してください。

タスクの進捗:

  • アダプティブな動作が必要な対象ウィジェットを特定する。
  • ウィジェットツリーを LayoutBuilder でラップする。
  • ビルダーコールバックから constraints.maxWidth を取得する。
  • アダプティブなブレークポイントを定義する(例:largeScreenMinWidth = 600)。
  • maxWidth > largeScreenMinWidth の場合: 大画面向けのレイアウトを返す(例:ナビゲーションサイドバーとコンテンツ領域を横並びに配置する Row)。
  • maxWidth <= largeScreenMinWidth の場合: 小画面向けのレイアウトを返す(例:Column または標準的なナビゲーション形式のレイアウト)。
  • バリデーターを実行 -> アプリケーションウィンドウのサイズを変更 -> レイアウトの切り替わりを確認 -> オーバーフローエラーを修正する。

ワークフロー:大画面向けの最適化

大きなディスプレイで UI 要素が不自然に横に広がらないよう、次のワークフローに従ってください。

タスクの進捗:

  • 全幅のコンポーネント(例:ListView、テキストブロック、フォーム)を特定します。
  • リストを最適化する場合: ListView.builder を SliverGridDelegateWithMaxCrossAxisExtent を使った GridView.builder に変換し、ウィンドウサイズに応じて列数が自動調整されるようにします。
  • フォームまたはテキストブロックを最適化する場合: コンポーネントを ConstrainedBox でラップします。
  • BoxConstraints(maxWidth: [optimal_width]) を ConstrainedBox に適用します。
  • ConstrainedBox を Center ウィジェットでラップし、大画面で制約されたコンテンツが中央に配置されるようにします。
  • バリデーターを実行 -> デスクトップ/タブレットのターゲットでテスト -> 横方向の伸びを確認 -> maxWidth またはグリッドの範囲を調整します。

例

LayoutBuilder を使ったアダプティブレイアウト

利用可能な幅に応じてモバイル向けレイアウトとデスクトップ向けレイアウトを切り替える方法を示します。

import 'package:flutter/material.dart';

const double largeScreenMinWidth = 600.0;

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

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth > largeScreenMinWidth) {
          return _buildLargeScreenLayout();
        } else {
          return _buildSmallScreenLayout();
        }
      },
    );
  }

  Widget _buildLargeScreenLayout() {
    return Row(
      children: [
        const SizedBox(width: 250, child: Placeholder(color: Colors.blue)),
        const VerticalDivider(width: 1),
        Expanded(child: const Placeholder(color: Colors.green)),
      ],
    );
  }

  Widget _buildSmallScreenLayout() {
    return const Placeholder(color: Colors.green);
  }
}
大画面での幅の制限

ウィジェットが水平方向のスペースをすべて使わないようにする方法を示します。

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ConstrainedBox(
          constraints: const BoxConstraints(
            maxWidth: 800.0, // Maximum width for readability
          ),
          child: ListView.builder(
            itemCount: 50,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text('Item $index'),
              );
            },
          ),
        ),
      ),
    );
  }
}

コメント