【Flutter】画面分割、パーセントで幅指定【日本語】

Flutterで画面の分割というかパーセント単位でエリアを区切るレイアウトをやってみた。

縦に2分割してみたり横に2分割してみたり……その備忘録。

※他のプログラミングに関する記事はこちら

 

スポンサーリンク

画面幅いっぱいのWidthとHeight

作ったアプリを表示させる機種等によって、画面サイズは異なる。

CSSとかだとWidthに100%とか指定すれば起動している端末の横幅いっぱいになったりするけど、Flutterだとパーセントでの指定がないっぽい。

Flutterで画面幅いっぱいのWidthとHeightを指定したい場合、MediaQuery.of(context).sizeを使えばいいみたい。

 

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {

    final double deviceHeight = MediaQuery.of(context).size.height;
    final double deviceWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
        height: deviceHeight,
        width: deviceWidth,
        color: Colors.green,
      )
    );
  }
}

 

結果

背景色が緑のコンテナが横幅も縦幅もいっぱいに広がった。

 

大事なのは34~35行目と42~43行目の記述。

MediaQuery.of(context).sizeを使えば、縦と横が画面幅いっぱいになるContainerが作成できる。

スポンサーリンク

画面を縦に2分割

画面を縦に2分割にしたい場合、ColumnとExpandedを使う。

以下例。

 

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {

    final double deviceHeight = MediaQuery.of(context).size.height;
    final double deviceWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            flex: 5, // 割合.
            child: Container(
              color: Colors.red,
            ),
          ),
          Expanded(
            flex: 5, // 割合.
            child: Container(
              color: Colors.blue,
            ),            
          )
        ]
      )
    );
  }
}

 

結果

赤と青で画面を2分割にしている。

 

大事なのは43~44行目。

Expandedウィジェットのflexに割合を指定している。

もう1つのExpandedウィジェットのflexにも割合を指定していて(50行目)今回の設定では5:5になるように画面領域を共有する。

 

 

ただ、ここで大事なのがContainerの特徴で、childが指定されているContainerの場合は出来る限り要素を小さくしようとする仕様があるらしい。

以下例。

 

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {

    final double deviceHeight = MediaQuery.of(context).size.height;
    final double deviceWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            flex: 5, // 割合.
            child: Container(
              color: Colors.red,
              child: Text("test")
            ),
          ),
          Expanded(
            flex: 5, // 割合.
            child: Container(
              color: Colors.blue,
            ),            
          )
        ]
      )
    );
  }
}

 

結果

 

childにTextウィジェットを埋め込んだ上半分だけ、横幅が最低限の大きさになってしまう。

正しい解決方法なのかわからないが、ColumnとExpandedを使った場合は横幅が小さくなろうとするので、Widthで画面幅いっぱいになるような指定をいれることで解決した(以下記述の46行目参照)

 

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {

    final double deviceHeight = MediaQuery.of(context).size.height;
    final double deviceWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            flex: 5, // 割合.
            child: Container(
              width: deviceWidth,
              color: Colors.red,
              child: Text("test")
            ),
          ),
          Expanded(
            flex: 5, // 割合.
            child: Container(
              color: Colors.blue,
            ),            
          )
        ]
      )
    );
  }
}

 

結果

スポンサーリンク

画面を横に2分割

画面を縦に2分割する際にはColumnを使っていたが、それをRowにするだけ。

Rowの場合、Containerのchildを設定すると縦幅が最低限になろうとするため、Heightを画面幅いっぱいに指定する。

以下例。

 

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {

    final double deviceHeight = MediaQuery.of(context).size.height;
    final double deviceWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Row(
        children: <Widget>[
          Expanded(
            flex: 5, // 割合.
            child: Container(
              height: deviceHeight,
              color: Colors.red,
              child: Text("test")
            ),
          ),
          Expanded(
            flex: 5, // 割合.
            child: Container(
              color: Colors.blue,
            ),            
          )
        ]
      )
    );
  }
}

 

結果

スポンサーリンク

組み合わせて使う。3分割使用

今まで紹介してきた方法を組み合わせて使うことで、恐らく大抵のレイアウトは組めるはず。

試しに以下みたいなレイアウトを組んでみた。

 

コードは以下の通り。

Expandedのflexは他のExpandedウィジェットのflexとの割合になるので、今回の場合だと横に並べている「赤」「青」「緑」の割合は2:6:2、真ん中に設置した縦に並べている「黄」「紫」「茶」の割合は1:1:1とすることで、上記図のようなレイアウトを実現している。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {

    final double deviceHeight = MediaQuery.of(context).size.height;
    final double deviceWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Row(
        children: <Widget>[
          Expanded(
            flex: 2, // 割合.
            child: Container(
              height: deviceHeight,
              color: Colors.red,
              child: Text("test")
            ),
          ),
          Expanded(
            flex: 6, // 割合.
            child: Container(
              color: Colors.blue,
              padding: EdgeInsets.fromLTRB(10, 30, 10, 30),
              child: Column(
                children: [
                  Expanded(
                    flex: 1, // 割合.
                    child: Container(
                      width: deviceWidth,
                      color: Colors.yellow,
                      child: Text("test")
                    ),
                  ),
                  Expanded(
                    flex: 1, // 割合.
                    child: Container(
                      width: deviceWidth,
                      color: Colors.purple,
                      child: Text("test")
                    ),
                  ),
                   Expanded(
                    flex: 1, // 割合.
                    child: Container(
                      width: deviceWidth,
                      color: Colors.brown,
                      child: Text("test")
                    ),
                  ),
                ],
              )
            ),            
          ),
          Expanded(
            flex: 2, // 割合.
            child: Container(
              color: Colors.green,
            ),            
          )
        ]
      )
    );
  }
}

 

他のプログラミングに関する記事

プログラミングまとめ

プログラミングに関する記事です。 言語とかツールごとにまとめています。 スポンサーリンク [adcode] Flutter ・簡単導入~サンプルアプリのデバック起動まで ・文字の表示(重ねて[…]

IMG

スポンサーリンク