Flutter:「FittedBox」の中だと「Row」の「mainAxisAlignment」が機能しない

※当サイトは、アフィリエイト広告を利用しています

結論:FittedBoxを個々のWidgetに対して設定する

2022/12/4 Flutter エラー・バグ日記

 

Widgetを横に並べる「Row」で、地味にハマってしまったので記録。

 

各Widgetを画面幅内に均等配置する「MainAxisAlignment.spaceEvenly」のプロパティを設定したが、どうしても左寄せになってしまい、機能しなかった。

 

 

本記事はライトな日記思考で書いているので、詳細説明はしておらず、基本、テキストのみで画像とかはあまり載せておりません。。m(_ _)m

解説記事ではないため、解決していない内容や、その時々の間違った解釈を述べてしまっている可能性が大いにありますので、何卒、ご了承ください。

 

実現したかったこと

各Widget(この例では2つのText Widget)が、所定のサイズをハミ出ないようにしつつ、左右に均等配置したかった。

 

この時点のコードは以下のとおり。ハミ出ないようにする部分には、「FittedBox」クラスの「fit: BoxFit.scaleDown」プロパティを使用した。

 

// クラス名、メソッド名、プロパティ名(変数名)について、筆者が作成したもの(名前変更可のもの)
// の名前の末尾には、大文字のオー「O」をつけています
// ※ライブラリ(パッケージ)で予め決められているもの(名前の変更不可のもの)と、
//  自分で作成したもの(名前の変更可のもの)の区別をしやすくするため

import 'package:flutter/material.dart';
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Test",
      theme: ThemeData.light(),
      home: SampleScreen(),
    );
  }
}

class SampleScreen extends StatefulWidget {
  @override
  _SampleScreenState createState() => _SampleScreenState();
}
class _SampleScreenState extends State<SampleScreen> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("TestApp"),
      ),
      body: Container(
          color: Colors.grey,
          height: 30.0,
          child:
            FittedBox(
            fit: BoxFit.scaleDown,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly, // ← これが機能しない
              children: [
                Container(
                  color: Colors.green,
                  child: Text("左のWidget", style: TextStyle(fontSize: 40.0)),
                ),
                Container(
                  color: Colors.yellow,
                  child: Text("右のWidget", style: TextStyle(fontSize: 40.0)),
                ),
              ],
            ),
          ),
        ),
    );
  }
}

 

ちなみに、「MainAxisAlignment.」の部分は、「.spaceEvenly」に限らず、「.start」や「.end」であっても、同様に全て左寄せになってしまう。

 

Containerで幅を規定したり、IntrinsicWidthでラップしたりするも変わらず

こちらの情報によると、幅が指定されていないことが原因とのこと。

 

 

そこで、親WidgetのContainerにwidthを設定してみたが、今度は2つのWidgetが中央に寄ってしまい、やはり均等配置できなかった。

 

また、「IntrinsicWidth」というクラスでラップしても解消できるそうなので、試してみたが、これも状況は変わらずだった。

 

FittedBoxが原因らしい

自分のコードでは、「Row」を「FiitedBox」でラップしているので、そのせいかもしれないと思い、調べてみると、下記情報を見つけた。

 

 

まさにズバリの内容。

 

しかし、期待した回答は示されておらず、「FittedBox」内では、「Row」の「mainAxisAlignment」は機能しないので、「SizedBox」を間に挟むなどして、Widgetの間隔を手動で広げるしか無いとのこと。 

 

「SizedBox」だと、間隔を固定値で設定することになるので、柔軟性に欠け、正直使用したくはない。。

 

FittedBox→Rowではなく、Row→FittedBoxの順番にしたら解消

画面幅に応じて、最適な間隔が設定されるような、もう少しスマートな方法が欲しい。。

 

考えた結果、個別のWidgetがサイズオーバーにならなければ良いので、Row全体をFittedBoxでラップするのではなく、Rowの中で、各Widgetを個別にFittedBoxでラップするよう変更してみた。

 

変更後のコードは以下のとおり。※変更部分にコメントを記載

 

import 'package:flutter/material.dart';
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Test",
      theme: ThemeData.light(),
      home: SampleScreen(),
    );
  }
}

class SampleScreen extends StatefulWidget {
  @override
  _SampleScreenState createState() => _SampleScreenState();
}
class _SampleScreenState extends State<SampleScreen> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("TestApp"),
      ),
      body: Container(
        color: Colors.grey,
        height: 30.0,
        // ここにあった FittedBox を削除
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            // 各 Text Widget を個別に FittedBox でラップ
            FittedBox(
              fit: BoxFit.scaleDown,
              child: Container(
                color: Colors.green,
                child: Text("左のWidget", style: TextStyle(fontSize: 40.0)),
              ),
            ),
            FittedBox(
              fit: BoxFit.scaleDown,
              child: Container(
                color: Colors.yellow,
                child: Text("右のWidget", style: TextStyle(fontSize: 40.0)),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

 

この方法により、無事、ハミ出しを抑えつつ、均等配置を実現できた。

 

 

FittedBox→Rowの順番だと機能しない理由

下記日記でも取り上げたが、

 

 

恐らく、「Container」クラスの公式情報の「Layout behavior」の項目のところに記載のある、

 

「Containerは、配置(alignment)を尊重し、子に合わせてサイズを調整し、幅、高さ、制約を尊重し、親に合わせて拡張し、可能な限り小さくしようとします。」(※Google翻訳を使用)

 

という内容が根拠だと思われる。

 

当初のコードだと、Container→FittedBox→Row→Text Widgetの順なので、FittedBoxができるだけRowを小さくしようとし、親であるContainerもそれに合わせて縮むので、結果、2つのText Widgetギリギリのサイズまで小さくなってしまったと思われる。

 

※Containerにはグレーの色を付けているが、冒頭の図ではグレーの部分が全く見えないことからも、Containerが2つのText Widgetギリギリまで縮んでいるのがわかる。

 

これに対し、Container→Row→FittedBox→Text Widgetの順に変えると、RowがFittedBoxの制約から逃れることができるため、Containerの幅が画面いっぱいまで広がり、その中で均等配置できるようになるのだろう。

 

サイズ関連の話は、Flutter熟練者の方々には常識の事かもしれないのだが、、手探りでやっていると、こういう基本的なことが未だに難しかったりする。。

 

\一般的なエラー対処法をまとめた記事はこちら/

 

リリースしたアプリ(全てFlutterで開発)

 

個人アプリ開発で役立ったもの

おすすめの学習教材

超初心者向けでオススメな元Udemyの講座/

 

 \キャンペーン時を狙えば安価で網羅的な内容が学べる(日本語訳あり)/

 

\Gitの基礎について無料で学べる/

 

おすすめの学習書籍

実用的image_pickerに関してかなり助けられた/

 

Dartの基礎文法を素早くインプットできる/


Dart入門 - Dartの要点をつかむためのクイックツアー

タイトルとURLをコピーしました