Flutter基礎 – Stackを使ってウィジェットを重ねる

Stackって何?

💡Stackとは…

A widget that positions its children relative to the edges of its box.

This class is useful if you want to overlap several children in a simple way, for example having some text and an image, overlaid with a gradient and a button attached to the bottom.

Stack class – widgets library – Dart API

ボックスの端を基準にして子を配置するウィジェット。

このクラスは、たとえば、テキストと画像を、グラデーションとボタンを下に貼り付けてオーバーレイするなど、簡単な方法で複数の子を重ねたい場合に役立ちます。

スタッククラス-ウィジェットライブラリ-Dart API

簡単に言うと

要素を重ねたいときに使用するウィジェット

です🙌

今回はStackについて学んでみましょう。

基本的な使い方

💡ポイント

  • Stackは簡単に複数のウィジェットを重ねることができるウィジェット。
  • 複数の子ウィジェット”を持つため、children引数リスト形式でウィジェットを渡す。
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('スタックサンプル'),
      ),
      body: Center(
        child: Stack(
          children: <Widget>[

            // 〜 コンテンツを配置する 〜

          ],
        ),
      ),
    );
  }
}

何も指定せずに配置

💡ポイント

  • 位置を指定せずに配置すると、”左上”に揃えられる。
  • 要素を重ねる際、リストの末尾に近いウィジェットが前面に配置される。
// 省略

      body: Center(
        child: Stack(
          children: <Widget>[

            // [後ろ]
            Container(
              color: Colors.deepOrange,
              height: 300.0,
              width: 300.0,
            ),

            // [真ん中]
            Container(
              color: Colors.orange,
              height: 250.0,
              width: 250.0,
            ),

            // [前面]
            Container(
              color: Colors.amber,
              height: 200.0,
              width: 200.0,
            ),
          ],
        ),
      ),

// 省略

位置を指定して配置 – AlignmentDirectional

上端揃えで配置 – top~

  • AlignmentDirectionalクラスのtop~定数を使用すると、上端を基準にして配置できる。
  • alignment:引数を指定していない場合、デフォルトは”AlignmentDirectional.topStart
// 省略
        child: Stack(
      // [ 左上 ]
          alignment: AlignmentDirectional.topStart,
          // [ 中央上 ]
          // alignment: AlignmentDirectional.topCenter,
          // [ 右上 ]
          // alignment: AlignmentDirectional.topBottom,
          children: <Widget>[
//省略

中心揃えで配置 – center~

  • AlignmentDirectionalクラスのcenter~定数を使用すると、中心を基準にして配置できる。
// 省略
        child: Stack(
      // [ 中心左 ]
          alignment: AlignmentDirectional.centerStart,
          // [ 中央 ]
          // alignment: AlignmentDirectional.center,
          // [ 中心右 ]
          // alignment: AlignmentDirectional.centerEnd,
          children: <Widget>[
//省略

下端揃えで配置 – bottom~

  • AlignmentDirectionalクラスのbottom~定数を使用すると、下端を基準にして配置できる。
// 省略
        child: Stack(
      // [ 左下 ]
          alignment: AlignmentDirectional.bottomStart,
          // [ 中央下 ]
          // alignment: AlignmentDirectional.bottomStart,
          // [ 右下 ]
          // alignment: AlignmentDirectional.bottomEnd,
          children: <Widget>[
//省略

自由な位置を基準に配置 – コンストラクタ

  • AlignmentDirectionalクラスのコンストラクタを使用すると、基準位置を自由に設定可能。
// 省略
        child: Stack(
      // [ 写真左端 ]
          alignment: AlignmentDirectional(1.0,2.0),
          // [ 写真左から2番目 ]
          // alignment: AlignmentDirectional(2.0,1.0),
          // [ 写真右から2番目 ]
          // alignment: AlignmentDirectional(-1.0,-2.0),
          // [ 写真右端 ]
          // alignment: AlignmentDirectional(-2.0,-1.0),
          children: <Widget>[
//省略

サイズの制約を変更する – StackFit

💡”サイズの制約”とは?

  • 例えば、Stackの親要素のSizedBox(子要素の大きさを決めるウィジェット)でStack自体のサイズ(height,width)が決められているとき、Stackの子要素のサイズは「0〜Stackのサイズ」の範囲に限られる。これを”サイズの制約”という。
//  省略

        child: SizedBox(

          // SizedBoxでStackのサイズを決める
          height: 250.0,
          width: 250.0,

          child: Stack(
            children: <Widget>[

              Container(
                // Stackのサイズ以上のサイズは設定できない
                // この場合は(height:250 width:250)に縮小されて表示される
                height: 300.0,
                width: 300.0,
              ),

              Container(
          // こちらのサイズはStackを超えていない
          // デフォルトの動作では200のまま表示される
                height: 200.0,
                width: 200.0,
              ),

            ],
          ),
        ),

// 省略

サイズの制約を緩和する – loose

💡ポイント

  • fit引数を渡さない場合のデフォルトの動作
  • 最大サイズStackのサイズに制限される
  • 最大サイズ以内であれば、子要素は自由にサイズを決められる
// 省略

        child: SizedBox(
          height: 300.0,
          width: 300.0,
          child: Stack(

            // サイズ制約を緩和
            fit: StackFit.loose,

            children: <Widget>[
              Container(
                color: Colors.deepOrange,
                height: 300.0,
                width: 300.0,
              ),
              Container(
                color: Colors.orange,
                height: 200.0,
                width: 200.0,
              ),
            ],
          ),
        ),
      ),

// 省略

●サイズが最大に引き伸ばされるexpand

💡ポイント

  • 最大サイズStackのサイズに制限される
  • すべての子要素はStackのサイズに引き伸ばされて表示される
// 省略

        child: SizedBox(
          height: 300.0,
          width: 300.0,
          child: Stack(

            // 子要素をStackサイズまで引き伸ばす
            fit: StackFit.expand,

            children: <Widget>[
              Container(
                color: Colors.deepOrange,
                height: 300.0,
                width: 300.0,
              ),
              Container(
                color: Colors.orange,
                height: 200.0,
                width: 200.0,
              ),
            ],
          ),
        ),
      ),

// 省略

子要素の位置を個別に指定する – Positioned

●Stackの中での位置を指定 – top/left/right/bottom

💡ポイント

  • alignmentは”子要素の配置基準を統一”するのに対し、Positionedは子要素の位置を個別に指定できる。

※Positionedについての詳しい設定方法は、また別記事で出そうと思います。

// 省略

        child: Stack(
          children: <Widget>[

            Container(
              color: Colors.deepOrange,
              height: 300.0,
              width: 300.0,
            ),

            Positioned(
              top: 50.0,
              right: 50.0,
              child: Container(
                color: Colors.orange,
                height: 100.0,
                width: 100.0,
              ),
            ),

            Positioned(
              bottom: 50.0,
              left: 50.0,
              child: Container(
                color: Colors.amber,
                height: 100.0,
                width: 100.0,
              ),
            ),

          ],
        ),

// 省略

はみ出した要素を切り取るかどうか – Overflow

  • 先程のPositionedで指定した子ウィジェットが、Stackのサイズを超えて”はみ出した”ときの動作を指定。

はみ出した部分を切り取る – clip

💡ポイント

  • overflow:引数に何も渡さなかった場合のデフォルトの動作
  • はみ出した部分を切り取った状態で表示する
// 省略

        child: Stack(

          // はみ出した部分を切り取る
          overflow: Overflow.clip,

          children: <Widget>[
            Container(
              color: Colors.deepOrange,
              height: 300.0,
              width: 300.0,
            ),
            Positioned(
              top: 100,
              left: 100,
              child: Container(
                color: Colors.orange,
                height: 250.0,
                width: 250.0,
              ),
            ),
          ],
        ),

// 省略

はみ出した部分を表示する – visible

💡ポイント

  • はみ出した部分をそのまま表示する
// 省略

        child: Stack(

          // はみ出した部分を表示する
          overflow: Overflow.visible,

          children: <Widget>[

// 省略