CodeZine(コードジン)

特集ページ一覧

Flutterでのレイアウトの組み合わせ方を学ぼう~実際の画面例を使用

Flutterで始めるモバイルアプリ開発 第12回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2021/09/28 11:00

 前回は、基本的な各レイアウトウィジェットについて説明しました。画面レイアウトはさまざまな組み合わせ方法があり、その組み合わせ方法によって気を付けるポイントなどが変わってしまいます。そこで、今回は実際の画面サンプルを例にどのようにレイアウトを使っていくかを紹介します。基本的なレイアウトは前回紹介したレイアウトを使いつつも、前回紹介出来なかったレイアウトもいくつか含まれています。それらはソースコードとして説明していきますが、足りない部分はリファレンスなどを参照してください。

目次

サンプルアプリケーションの概要

 今回作成するアプリは図1のようなもので、こちらを作成するサンプルを通じてレイアウトの紹介をしていきます。

 このような一覧表示とその詳細という画面構成は、スマホアプリでよくあるのではないかと思います。実際には細かい部分の装飾をより行うわけですが、構成の基本はよく使われているはずです。

図1:サンプルアプリケーションの画面
図1:サンプルアプリケーションの画面

一覧画面の作成

 一覧画面を作成するためにレイアウト構成を決め、その構成に合わせてコードを作成していきます。

一覧画面のレイアウト構成

 一覧画面での各レイアウト構成を記したものが図2です。一覧として表示される部品は、今回はあくまでレイアウトのサンプルということで固定で作成しています。しかし、多くの場合ではデータをネットワーク上からロードし表示するようなことになる想定です。

 従って、実際には、表示するアイテム数が何個になるのかはプログラム作成時にはわからないということになります。その点が、前回紹介したColumnレイアウトと違うところですが、それ以外はColumn/Rowレイアウトが利用可能な配置方法になります。

図2:一覧表示の画面のレイアウト概要
図2:一覧表示の画面のレイアウト概要

ListViewを使ったレイアウト

 一覧画面を作成する際に、よく使うレイアウトの1つがListViewというレイアウトウィジェットです。このListViewウィジェットは一般的にスクロールが必要なレイアウトに対して使用します。

 このウィジェットを使う利点は、画面表示に必要な部分のみの描画が可能になるため全体の表示件数が多くても、表示されている部分のみの描画ですみます。

 リスト1が実際にListViewを使ったコード例です。

[リスト1] ListViewを使ったサンプルコード(lib/list/CouponListView.dartの抜粋)
class CouponListView extends StatelessWidget{

  Function onPressed;
  CouponListView(this.onPressed);

  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.white,
        // (1) ListViewを配置する
        child: listViewBuilder()
    );
  }

  // (2) 固定数で表示する
  Widget buildListView(){
    return ListView(
      children: [
        CouponListItem(onPressed),
        CouponListItem(onPressed),
        CouponListItem(onPressed),
      ],
    );
  }

  //  (3) データの個数に従って、表示する場合
  final items = [0,1,2,3,4,5,6];
  //  (4) ListView.builder()を代わりに使う
  Widget listViewBuilder(){
    return ListView.builder(
      // (5) データ個数
      itemCount: items.length,
      // (6) 表示するウィジェット
      itemBuilder: (BuildContext context, int index) {
        return CouponListItem(onPressed);
      }
    );
  }
}

 (1)でListViewウィジェットContainerウィジェットの子ウィジェットとして配置しています。(2)はColumnウィジェットと同じようにあらかじめ表示する子ウィジェットが作成できる場合に使う方法です。

 しかし、本来やりたいことは、表示するデータを外部から取得することです。そこで、データを(3)のように疑似的に用意しています。

 そして、このデータに応じて表示するには、(4)のようにListView.builder()コンストラクタを使います。(4)itemCountでデータ個数を設定し、(5)itemBuilderで表示するウィジェットを作成方法を設定します。

 コードを実行した結果が図3のようになります。

図3:ListViewサンプルコードの実行結果
図3:ListViewサンプルコードの実行結果

親ウィジェットのサイズに応じて表示サイズを調整する

 続いて、一覧内の表示する中身であるCouponListItemについて作成していきます。この自作ウィジェットでは、画像とその右側に表示される領域に分けてレイアウトをします。その際に、図4のような課題があります。

図4:CouponListItemウィジェットを作る際のレイアウト構成と課題
図4:CouponListItemウィジェットを作る際のレイアウト構成と課題

 画像は100x100の正方形として表示する前提ですが、用意する画像が必ずしも正方形とは限らないケースがあります。そのようなケースを想定し、はみ出した部分は自動的に表示しないようにしたいと思います。そして、右側の領域は、画面サイズに応じて広がる領域として作成します。この例のように、固定サイズと自動で広がる領域の組み合わせというケースはよく見るレイアウト形式です。

 このレイアウトを実装したコードがリスト2です。

[リスト2] CouponListViewContainerの基本プロパティ(lib/list/CouponListItem.dartからの抜粋)
Widget build(BuildContext context) {

  return Container(
    margin: EdgeInsets.all(10),
    padding: EdgeInsets.all(10),
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(10),
      color: Colors.white,
      boxShadow: [BoxShadow(color: Colors.grey, blurRadius: 3)]),

      // (1) 縦方向に並べる
      child: Row(
        children: [
          Container(
            // (1)画像を配置
            width: 100,
            height: 100,
            child: imageWidget(),
            // : (省略)
          ),
          // (2) 自動的に広がる
          Expanded(
            child: Container(
              height: 100,
              child: MainContent(onPressed)
            )
          )
        ]));
}

//  (3) 画像を表示
Widget imageWidget(){
  return ClipRect(
    child: FittedBox(
      child: Image.asset('assets/images/c_img3.jpg'),
        fit: BoxFit.cover,
    )
  );
}

 (1)では、Rowウィジェットを使って横に並べます。(1)の場所に100x100サイズで画像を配置します。ただし、詳細については後述します。(2)ではサイズを広げるExpandedレイアウトを使います。

 そして、画像ですが、そのまま画像(Imageウィジェット)を配置すると自動でリサイズされすべてが表示されるように縮小されていまいます。

 この振る舞いを変えるにはFittedBoxを使います。このウィジェットは、子ウィジェットが親ウィジェットとサイズが異なる場合にどのようにサイズを調整するかを指定できます。

 画像を目的のサイズに調整する方法は、fitプロパティで指定可能で、表1の値が指定可能です。実際に画像がどのような振る舞いになるかはリファレンスを見ると分かります。

 HTML/CSSを知っている方であれば、background-image-sizeのようなことができるとイメージしていただければと思います。注意すべき点は、親サイズからはみ出して表示されてしまうということです。その場合にはみ出した部分を消してくれるのがClipRectです。

表1:FittedBoxのfitで指定できるプロパティ値
プロパティ値 説明
contain
親ウィジェットのサイズに合わせてすべて収まるように表示します。
cover
親ウィジェットの縦、もしくは横のサイズに合わせて隙間がないようにリサイズします。ただし、はみ出した部分も表示されてしまいます。
fill
親ウィジェットの縦と横の双方のサイズに合わせて隙間がないようにリサイズします。
fitWidth
親ウィジェットの横のサイズにリサイズします。ただし、はみ出した部分も表示されてしまいます。
fitHeight 親ウィジェットの縦のサイズにリサイズします。ただし、はみ出した部分も表示されてしまいます。
none
親ウィジェットにかかわらずサイズを変更せずに表示します。ただし、はみ出した部分も表示されてしまいます。
scaleDown containとほぼ同様ですが、親ウィジェットのサイズより小さいときには拡大されることはありません。

親ウィジェットのサイズに応じてフォントサイズを調整する

 そして、画像の右領域を表示するウィジェットはMainContentというウィジェットを自作しています。このウィジェットは基本的にColumn/Rowレイアウトで可能です。

 実際には装飾などがあり長いコードとなりますが、このウィジェットは基本的にColumn/Rowレイアウトで可能です。そのため、詳細は割愛します。

 しかし、先ほどと同様にサイズに合わせてフォントサイズを変更する箇所があります。

 その際には、先ほども使ったFittedBoxを使うと可能です。このようにFittedBoxはサイズ調整する際に非常に便利なレイアウトです。

[リスト3] フォントのサイズ調整をするコード例(lib/list/MainContent.dartからの抜粋)
FittedBox(
  fit: BoxFit.contain,
  child: Text("詳細を見る"),
),

  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:Flutterで始めるモバイルアプリ開発

もっと読む

著者プロフィール

  • WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。個人紹介主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしど...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5