🫡

MediaQueryについて学んでみる

2023/02/21に公開

端末ごとのサイズ調整したい

MediaQueryを使うとスマートフォンの画面の幅と高さのサイズを取得できます。これを使うとどんなメリットがあるのかというと、テックフォードアカデミーの学生さんによると、サイズ調整ができるContainerと組み合わせて、端末ごとのズレを無くすことに役立つようです。
実際に使ってみて検証してみました!

こちらは以前書いていたソースコード

import 'package:flutter/material.dart';

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

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

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const DummyBuy(),
    );
  }
}

class DummyBuy extends StatefulWidget {
  const DummyBuy({Key? key}) : super(key: key);

  
  State<DummyBuy> createState() => _DummyBuyState();
}

class _DummyBuyState extends State<DummyBuy> {
  int counter = 0;

  void decrement() {
    setState(() {
      counter--;
    });
  }

  void increment() {
    setState(() {
      counter++;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text('予約する'),
      ),
      body: SingleChildScrollView(
        child: Center(
          child: Column(
            children: <Widget>[
              SizedBox(height: 20),
              Container(
                color: Colors.grey,
                width: 300,
                height: 150,
              ),
              SizedBox(height: 10),
              Container(width: 300, child: Text('ショートケーキ5号')),
              SizedBox(height: 10),
              Container(
                  width: 300,
                  child: Text('直径15cm、4〜6人分です。フルーツがいっぱいのっている贅沢なケーキです。')),
              SizedBox(height: 20),
              Container(
                width: 300,
                child: TextFormField(
                  maxLines: 5,
                  keyboardType: TextInputType.multiline,
                  decoration: InputDecoration(
                      hintText:
                          "(例)食物アレルギーでキゥイがダメ、メッセージプレートの内容が、英語でHappy Birthday",
                      border: OutlineInputBorder()),
                ),
              ),
              SizedBox(height: 20),
              Container(
                width: 300,
                child: Row(
                  children: [
                    TextButton(
                        onPressed: () {
                          decrement();
                        },
                        child: const Text('-', style: TextStyle(fontSize: 20))),
                    const SizedBox(width: 10),
                    Text(counter.toString()),
                    const SizedBox(width: 10),
                    TextButton(
                        onPressed: () {
                          increment();
                        },
                        child: const Text('+', style: TextStyle(fontSize: 20))),
                  ],
                ),
              ),
              const SizedBox(height: 20),
              ElevatedButton(onPressed: () {}, child: const Text('カートに追加する')),
            ],
          ),
        ),
      ),
    );
  }
}

これは、無駄があったりした!
各所にContainerで囲んだWidgetがあります。トップレベルのColumnをcontainerでラップして横幅を指定するといい感じになるとのこと!


設定を変えてみる

MediaQueryを使ってみて端末ごとにレイアウトを変えてみる。タブレットは別の設定が必要なので、これだけでは、対応できなかったですね😅

iPhone13

import 'package:flutter/material.dart';

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

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

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const FormExample(),
    );
  }
}

class FormExample extends StatelessWidget {
  const FormExample({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    final deviceWidth = MediaQuery.of(context).size.width;
    final deviceHeight = MediaQuery.of(context).size.height;
    print('width: $deviceWidth'); // flutter: width: 375.0
    print('height $deviceHeight'); // flutter: height 812.0
    return Scaffold(
      appBar: AppBar(
        title: const Text('Form'),
      ),
      body: SingleChildScrollView(
        child: Center(
          child: Container(
            width: deviceWidth * 0.8,
            child: Column(
              children: <Widget>[
                SizedBox(height: 20),
                Container(
                  color: Colors.grey,
                  width: 300,
                  height: 150,
                ),
                SizedBox(height: 10),
                Container(width: deviceWidth * 0.8, child: Text('ショートケーキ5号')),
                SizedBox(height: 10),
                Text('直径15cm、4〜6人分です。フルーツがいっぱいのっている贅沢なケーキです。'),
                SizedBox(height: 20),
                TextFormField(
                  maxLines: 5,
                  keyboardType: TextInputType.multiline,
                  decoration: InputDecoration(
                      hintText:
                      "(例)食物アレルギーでキゥイがダメ、メッセージプレートの内容が、英語でHappy Birthday",
                      border: OutlineInputBorder()),
                ),
                SizedBox(height: 20),
                Row(
                  children: [
                    TextButton(
                        onPressed: () {},
                        child: const Text('-', style: TextStyle(fontSize: 20))),
                    const SizedBox(width: 10),
                    TextButton(
                        onPressed: () {},
                        child: const Text('+', style: TextStyle(fontSize: 20))),
                  ],
                ),
                const SizedBox(height: 20),
                ElevatedButton(onPressed: () {}, child: const Text('カートに追加する')),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

iPhone13 mini

import 'package:flutter/material.dart';

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

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

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const FormExample(),
    );
  }
}

class FormExample extends StatelessWidget {
  const FormExample({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    final deviceWidth = MediaQuery.of(context).size.width;
    final deviceHeight = MediaQuery.of(context).size.height;
    print('width: $deviceWidth'); // flutter: width: 375.0
    print('height $deviceHeight'); // flutter: height 812.0
    return Scaffold(
      appBar: AppBar(
        title: const Text('Form'),
      ),
      body: SingleChildScrollView(
        child: Center(
          child: Container(
            width: deviceWidth * 0.8,
            child: Column(
              children: <Widget>[
                SizedBox(height: 20),
                Container(
                  color: Colors.grey,
                  width: 300,
                  height: 150,
                ),
                SizedBox(height: 10),
                Container(width: deviceWidth * 0.8, child: Text('ショートケーキ5号')),
                SizedBox(height: 10),
                Text('直径15cm、4〜6人分です。フルーツがいっぱいのっている贅沢なケーキです。'),
                SizedBox(height: 20),
                TextFormField(
                  maxLines: 5,
                  keyboardType: TextInputType.multiline,
                  decoration: InputDecoration(
                      hintText:
                          "(例)食物アレルギーでキゥイがダメ、メッセージプレートの内容が、英語でHappy Birthday",
                      border: OutlineInputBorder()),
                ),
                SizedBox(height: 20),
                Row(
                  children: [
                    TextButton(
                        onPressed: () {},
                        child: const Text('-', style: TextStyle(fontSize: 20))),
                    const SizedBox(width: 10),
                    TextButton(
                        onPressed: () {},
                        child: const Text('+', style: TextStyle(fontSize: 20))),
                  ],
                ),
                const SizedBox(height: 20),
                ElevatedButton(onPressed: () {}, child: const Text('カートに追加する')),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

iPhone13 Pro Mac

import 'package:flutter/material.dart';

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

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

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const FormExample(),
    );
  }
}

class FormExample extends StatelessWidget {
  const FormExample({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    final deviceWidth = MediaQuery.of(context).size.width;
    final deviceHeight = MediaQuery.of(context).size.height;
    print('width: $deviceWidth'); // flutter: width: 428.0
    print('height $deviceHeight'); // flutter: height 926.0
    return Scaffold(
      appBar: AppBar(
        title: const Text('Form'),
      ),
      body: SingleChildScrollView(
        child: Center(
          child: Container(
            width: deviceWidth * 0.8,
            child: Column(
              children: <Widget>[
                SizedBox(height: 20),
                Container(
                  color: Colors.grey,
                  width: 300,
                  height: 150,
                ),
                SizedBox(height: 10),
                Container(width: deviceWidth * 0.8, child: Text('ショートケーキ5号')),
                SizedBox(height: 10),
                Text('直径15cm、4〜6人分です。フルーツがいっぱいのっている贅沢なケーキです。'),
                SizedBox(height: 20),
                TextFormField(
                  maxLines: 5,
                  keyboardType: TextInputType.multiline,
                  decoration: InputDecoration(
                      hintText:
                          "(例)食物アレルギーでキゥイがダメ、メッセージプレートの内容が、英語でHappy Birthday",
                      border: OutlineInputBorder()),
                ),
                SizedBox(height: 20),
                Row(
                  children: [
                    TextButton(
                        onPressed: () {},
                        child: const Text('-', style: TextStyle(fontSize: 20))),
                    const SizedBox(width: 10),
                    TextButton(
                        onPressed: () {},
                        child: const Text('+', style: TextStyle(fontSize: 20))),
                  ],
                ),
                const SizedBox(height: 20),
                ElevatedButton(onPressed: () {}, child: const Text('カートに追加する')),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

iPhone SE

import 'package:flutter/material.dart';

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

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

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const FormExample(),
    );
  }
}

class FormExample extends StatelessWidget {
  const FormExample({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    final deviceWidth = MediaQuery.of(context).size.width;
    final deviceHeight = MediaQuery.of(context).size.height;
    print('width: $deviceWidth'); // flutter: width: 375.0
    print('height $deviceHeight'); // flutter: height 667.0
    return Scaffold(
      appBar: AppBar(
        title: const Text('Form'),
      ),
      body: SingleChildScrollView(
        child: Center(
          child: Container(
            width: deviceWidth * 0.8,
            child: Column(
              children: <Widget>[
                SizedBox(height: 20),
                Container(
                  color: Colors.grey,
                  width: 300,
                  height: 150,
                ),
                SizedBox(height: 10),
                Container(width: deviceWidth * 0.8, child: Text('ショートケーキ5号')),
                SizedBox(height: 10),
                Text('直径15cm、4〜6人分です。フルーツがいっぱいのっている贅沢なケーキです。'),
                SizedBox(height: 20),
                TextFormField(
                  maxLines: 5,
                  keyboardType: TextInputType.multiline,
                  decoration: InputDecoration(
                      hintText:
                          "(例)食物アレルギーでキゥイがダメ、メッセージプレートの内容が、英語でHappy Birthday",
                      border: OutlineInputBorder()),
                ),
                SizedBox(height: 20),
                Row(
                  children: [
                    TextButton(
                        onPressed: () {},
                        child: const Text('-', style: TextStyle(fontSize: 20))),
                    const SizedBox(width: 10),
                    TextButton(
                        onPressed: () {},
                        child: const Text('+', style: TextStyle(fontSize: 20))),
                  ],
                ),
                const SizedBox(height: 20),
                ElevatedButton(onPressed: () {}, child: const Text('カートに追加する')),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

まとめ

Containerでラップして幅を300でベタ書きして設定していたのですが、端末ごとの幅を取得して×0.8ぐらいにしてサイズの異なる端末ごとに設定すると、いい感じのレイアウトになった気がします。
もっと綺麗なレイアウトをできるように、サイズ調整のテクニックを学ばなくてはならないと、情報系の学生さんから学べました。
シェアハウスで暮らしていないと、コードレビューもないですから他の書き方もあるよなと、気づかずに自己流になっていましたね。
もっといいコードを書きたい。

Discussion