2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Widget (Flutter Roadmap Widgets)

Last updated at Posted at 2023-09-18

はじめに

Flutterを網羅的に学習するにあたってRoadmapを使って学習を進めることにしました。

この記事では、Flutter初学者やこれからFlutterを学習し始める方に向けて、Widgetsについてまとめています。

RoadmapはFlutterだけでなく、他の言語やスキルのロードマップも提供されており、何から学習して良いか分からないと悩んでいる方にとって有用なサイトになっています。
ぜひRoadmapを利用して学習してみてください。

Roadmapとは

簡潔に言えば、Roadmap.shは学習者にとってのガイドブックであり、学習の方向性を提供する学習ロードマップサイトです。

初心者から上級者まで、ステップバイステップでスキルを習得するための情報が提供されています。

学習の進め方が分かりやすく示されているだけでなく、個々の項目に参考資料やリソースへのリンクも提供されているので、学習者は目標を設定し、自分自身のペースで学習を進めることができます。

Flutter IDE

FlutterロードマップWidgetsでは以下の21のサイトが紹介されています。興味のある方はぜひお読みください。

Widgetとは

Widgetは、アプリのビューを構築するための要素です。画面上に表示されるコンポーネント1、レイアウト、スタイルなどを表現します。Flutterでは、Widgetを組み合わせることによって、複雑なUIを作成することができます。
それぞれのWidget毎にプロパティ2が予め用意されており、色を変えたり、大きさを調整したりなどはすべてWidgetが持つプロパティに設定していきます。

基本 Widget

Text

テキストを表示するための基本的なウィジェットです。

  • Textコンテンツ
    文字列を表示するためにtextプロパティにテキストコンテンツを指定します。
Text("Flutter");
  • Textスタイル
    テキストのスタイル(フォント、サイズ、色など)をカスタマイズするために、styleプロパティを使用します。
Text(
  "カスタムテキストスタイル",
  style: TextStyle(
    fontSize: 20.0,
    fontWeight: FontWeight.bold,
    color: Colors.blue,
  ),
);
  • Textの配置
    テキストウィジェットのデフォルトの配置は左寄せですが、textAlignプロパティを使用してテキストの配置を調整できます。
Text(
  "中央揃えテキスト",
  textAlign: TextAlign.center,
);
  • Textの改行
    デフォルトでは、長いテキストは自動的に改行されます。\nを使用して手動で改行を挿入することもできます。
Text(
  "1行目\n2行目\n3行目",
);
  • Textの装飾
    decorationプロパティを使用して、テキストに下線や取り消し線などの装飾を追加できます。また、decorationColorやdecorationStyleを使用して、それらの装飾の色やスタイルをカスタマイズすることもできます。
Text(
  "下線付きテキスト",
  style: TextStyle(
    decoration: TextDecoration.underline,
    decorationColor: Colors.red,
    decorationStyle: TextDecorationStyle.dotted,
  ),
);
  • フォントのカスタマイズ
    fontFamilyプロパティを使用して、特定のフォントファミリーを指定できます。
Text(
  "カスタムフォント",
  style: TextStyle(
    fontFamily: "MyCustomFont",
  ),
);

Image

画像を表示するために使用されるウィジェットです。アプリケーション内のローカル画像や、ネットワークからのリモート画像を表示するために利用できます。

  • ローカル画像の表示
    ローカルに保存された画像を表示する場合、プロジェクト内のassetsフォルダなどから画像を読み込みます。AssetImageを使用して、画像を指定します。
Image(
  image: AssetImage('assets/images/my_image.png'),
)

また、画像を表示するにはpubspec.yamlファイルでアセットを指定する必要があります。

  • ネットワークからの画像の表示
    ネットワーク上の画像を表示する場合、NetworkImageを使用します。URLを指定して画像を読み込みます。
Image(
  image: NetworkImage('https://example.com/my_image.jpg'),
)
  • 画像のサイズ変更
    widthおよびheightプロパティを使用して、画像のサイズを変更できます。
Image(
  image: AssetImage('assets/images/my_image.png'),
  width: 200.0,
  height: 150.0,
)
  • フィットモード
    fitプロパティを使用して、画像のフィットモードを設定できます。例えば、BoxFit.coverは画像をアスペクト比3を保持したまま最大まで表示します。
Image(
  image: AssetImage('assets/images/my_image.png'),
  width: 200.0,
  height: 150.0,
  fit: BoxFit.cover,
)
  • エラープレースホルダー
    errorBuilderプロパティを使用して、画像の読み込みに失敗した場合に表示するカスタムのウィジェットを指定できます。これにより、エラー処理をカスタマイズできます。
Image(
  image: NetworkImage('https://example.com/my_image.jpg'),
  errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
    return Text('画像を読み込めませんでした');
  },
)

Button

ユーザーがアプリケーション内でアクションを実行する際に使用するウィジェットです。ボタンをタップすることで、特定の動作や処理がトリガーされます。

onPressedプロパティを使用してボタンが押されたときに実行されるコールバック関数を指定します。また、childプロパティを使用してボタン内に表示されるコンテンツ(テキストまたはアイコン)を指定します。

ボタンウィジェットを選択する際には、アプリケーションのUIやUXに合わせて適切なタイプを選択することが重要です。

  • ElevatedButton
    標準的な浮き上がったボタンを表現するためのウィジェットです。通常は、重要なアクションや主要な操作を示すために使用されます。
ElevatedButton(
  onPressed: () {
    // ボタンが押されたときの処理
  },
  child: Text('Elevated Button'),
)
  • TextButton
    テキストスタイルのボタンを表現するためのウィジェットです。通常は、補助的なアクションやリンクを示すために使用されます。
TextButton(
  onPressed: () {
    // ボタンが押されたときの処理
  },
  child: Text('Text Button'),
)
  • OutlinedButton
    ボタンの外側にアウトラインを持つウィジェットです。通常は、中程度のアクションを示すために使用されます。
OutlinedButton(
  onPressed: () {
    // ボタンが押されたときの処理
  },
  child: Text('Outlined Button'),
)
  • IconButton
    アイコンを含むボタンを表現するためのウィジェットです。通常は、アイコンをタップしてアクションをトリガーするために使用されます。
IconButton(
  onPressed: () {
    // ボタンが押されたときの処理
  },
  icon: Icon(Icons.star),
)

Container

他のウィジェットを包むコンテナやレイアウトの要素として使用されます。

Containerの基本プロパティ

プロパティ 内容
child 単一のWidgetを作成
color 色の指定
alignment child Widgetの位置を指定
height/width 高さ/幅の指定
margin 外側の余白を指定
padding 内側の余白を指定
decoration 外観をカスタマイズ
Container(
      width: 200.0,
      height: 150.0,
      alignment: Alignment.center,
      margin: EdgeInsets.all(20.0),
      padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(color: Colors.black, width: 2.0),
        borderRadius: BorderRadius.circular(10.0),
        boxShadow: [
          BoxShadow(
            color: Colors.grey,
            blurRadius: 5.0,
          ),
        ],
      ),
      child: Text(
        'Container',
        style: TextStyle(
          fontSize: 18.0,
          color: Colors.white,
        ),
      ),
    );

Card

カードを表示するために使用されるウィジェットです。通常、情報をコンパクトに表示し、影や角丸などのスタイルを持つ要素として利用されます。

Cardの基本プロパティ

プロパティ 説明
child カード内に表示するコンテンツを指定
elevation カードの影の深さを設定
shape カードの形状をカスタマイズ
margin カードの周りの余白を設定
color カードの背景色を指定
  • child
    Card内に表示するコンテンツを指定します。Text、Imageなどのウィジェットを含めることが多いですが、他のウィジェットも含めることができます。
Card(
  child: Column(
    children: <Widget>[
      Text('カードのタイトル'),
      Text('カードの内容'),
    ],
  ),
)
  • elevation
    カードの影の深さを設定します。値を大きくするほど、カードが浮き上がって見えます。デフォルト値は2.0です。
Card(
  elevation: 5.0,
  child: /* ... */,
)
  • shape
    カードの形状をカスタマイズできます。RoundedRectangleBorderやBeveledRectangleBorderを使用して、角丸や斜めの角を持つカードを作成します。
Card(
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(15.0),
  ),
  child: /* ... */,
)
  • margin
    カードの周りの余白を設定します。他の要素との間にスペースを追加するために使用されます。
Card(
  margin: EdgeInsets.all(10.0),
  child: /* ... */,
)
  • color
    カードの背景色を指定できます。通常、カードに色を設定することはありませんが、必要に応じて使用できます。
Card(
  color: Colors.blue,
  child: /* ... */,
)

Column / Row

画面上のウィジェットの配置と整列を制御するために使用されます。

Columnウィジェット

子要素を垂直に配置するためのウィジェットです。縦に並ぶウィジェットのグループを作成するのに使用されます。childrenプロパティにColumn内に配置するウィジェットをリストで指定します。

Column(
  children: <Widget>[
    Text('項目1'),
    Text('項目2'),
    Text('項目3'),
  ],
)

子要素が上から下に順番に配置され、親要素の幅に合わせて伸縮します。

Rowウィジェット

子要素を水平に配置するためのウィジェットです。横に並ぶウィジェットのグループを作成するのに使用されます。childrenプロパティにRow内に配置するウィジェットをリストで指定します。

Row(
  children: <Widget>[
    Text('アイコン'),
    Text('テキスト'),
  ],
)

子要素が左から右に順番に配置され、親要素の高さに合わせて伸縮します。

ColumnとRowウィジェットを使用したサンプルコード

Column(
  children: <Widget>[
    Text('タイトル'),
    Text('サブタイトル'),
    Row(
      children: <Widget>[
        Icon(Icons.star),
        Text('5.0'),
      ],
    ),
  ],
)

ListView

スクロール可能なリストを作成するためのウィジェットです。大量のアイテムをスクロール可能なリストとして表示することができます。

ListViewの基本プロパティ

プロパティ 説明
children ListView内に配置する子要素のリストを指定
scrollDirection ListViewのスクロール方向を設定
itemBuilder 動的なリストを生成する
itemCount ListView.builderを使用する場合、生成するアイテムの総数を指定
physics スクロールの挙動を制御する
  • children
    childrenプロパティは、ListView内に配置する子要素(ウィジェット)のリストを指定します。これらの子要素は通常、リスト内に表示される個々のアイテムです。
ListView(
  children: <Widget>[
    ListTile(title: Text('アイテム1')),
    ListTile(title: Text('アイテム2')),
    // 他のアイテム...
  ],
)
  • scrollDirection
    ListViewのスクロール方向を設定します。デフォルトでは垂直方向(Axis.vertical)ですが、水平方向にスクロールしたい場合はAxis.horizontalを使用します。
ListView(
  scrollDirection: Axis.horizontal,
  children: <Widget>[
    ListTile(title: Text('アイテム1')),
    ListTile(title: Text('アイテム2')),
    // 水平に並ぶアイテム...
  ],
)
  • itemBuilder
    動的なリストを生成する場合にカスタムアイテムを生成する関数を指定できます。ListView.builderと組み合わせて使用されます。
ListView.builder(
  itemCount: items.length,
  itemBuilder: (BuildContext context, int index) {
    return ListTile(title: Text(items[index]));
  },
)
  • itemCount
    ListView.builderを使用する場合に生成するアイテムの総数を指定します。
ListView.builder(
  itemCount: items.length,
  itemBuilder: (BuildContext context, int index) {
    return ListTile(title: Text(items[index]));
  },
)

itemBuilderitemCountに関してわかりやすい記事があったので、是非読んでみてください。

  • physics
    スクロールの挙動を制御するために使用されます。例えば、スクロールの動きやバウンスなどをカスタマイズできます。
ListView(
  physics: BouncingScrollPhysics(),
  children: <Widget>[
    // アイテム...
  ],
)

AppBar

アプリケーションの上部に表示されるアプリケーションバーを作成するためのウィジェットです。アプリケーションのタイトル、アイコン、アクションボタン、その他メニューアイテムを配置することが一般的です。

AppBarの基本プロパティ

プロパティ 説明
title アプリケーションバーに表示されるタイトルを設定
actions アプリケーションバーに表示されるアイコンボタンやメニューアイテムのリストを指定
leading アプリケーションバーの左端に表示される要素を指定
backgroundColor アプリケーションバーの背景色を設定
elevation アプリケーションバーの影の深さを設定
  • title
    アプリケーションバーに表示されるタイトルを設定します。
AppBar(
  title: Text('My App'),
)
  • actions
    アプリケーションバーに表示されるアクションボタン(アイコンボタンやメニューアイテム)のリストを指定します。
AppBar(
  actions: <Widget>[
    IconButton(
      icon: Icon(Icons.search),
      onPressed: () {
        // 検索アクションの処理
      },
    ),
    IconButton(
      icon: Icon(Icons.settings),
      onPressed: () {
        // 設定アクションの処理
      },
    ),
  ],
)
  • leading
    アプリケーションバーの左端に表示される要素を指定します。ハンバーガーメニューアイコンなどを配置する際に多く使用されます。
AppBar(
  leading: IconButton(
    icon: Icon(Icons.menu),
    onPressed: () {
      // メニューアクションの処理
    },
  ),
)
  • backgroundColor
    アプリケーションバーの背景色を設定します。
AppBar(
  backgroundColor: Colors.blue,
)
  • elevation
    アプリケーションバーの影の深さを設定します。値を大きくするほど、アプリケーションバーが浮き上がって見えます。
AppBar(
  elevation: 4.0,
)

Scaffold

Scaffoldは「足場」という意味になりますが、アプリ画面でよく使われるメニュー表示方法を含めて画面全体を管理するウィジェットです。

Scaffoldの基本プロパティ

プロパティ 説明
appBar AppBarウィジェットを指定
body 画面の本文コンテンツを指定
drawer ハンバーガーメニューを指定
floatingActionButton 画面のフローティングアクションボタンを指定
floatingActionButtonLocation フローティングアクションボタンの位置を設定
persistentFooterButtons 画面の下部に固定されるボタンのリストを指定
backgroundColor Scaffoldの背景色を設定
resizeToAvoidBottomInset キーボードが表示されたときにコンテンツをスクロールするかどうかを設定
extendBody bodyコンテンツを画面の下部まで拡張するかどうかを制御
extendBodyBehindAppBar appBarの下にコンテンツを表示するかどうかを制御
  • appBar
    AppBarウィジェットを指定します。アプリケーションの上部に表示され、通常はタイトルやアクションボタンを含みます。
Scaffold(
  appBar: AppBar(
    title: Text('My App'),
  ),
  // 他のウィジェットを含む
)
  • body
    画面の本文コンテンツを指定します。ページの中身やリストビュー、フォームなどを含みます。
Scaffold(
  body: Center(
    child: Text('Hello, World!'),
  ),
  // 他のウィジェットを含む
)
  • drawer
    ハンバーガーメニューを指定します。通常、サイドバーのナビゲーションメニューや設定メニューを表示するのに使用されます。
Scaffold(
  appBar: AppBar(
    title: Text('My App'),
  ),
  drawer: Drawer(
    // ハンバーガーメニューの内容を指定
  ),
  // 他のウィジェットを含む
)
  • floatingActionButton
    画面のフローティングアクションボタンを指定します。主要なアクションや追加操作を実行するために使用されます。
Scaffold(
  appBar: AppBar(
    title: Text('My App'),
  ),
  floatingActionButton: FloatingActionButton(
    onPressed: () {
      // フローティングアクションの処理
    },
    child: Icon(Icons.add),
  ),
  // 他のウィジェットを含む
)
  • floatingActionButtonLocation
    フローティングアクションボタンの配置を制御します。設定には次のようなものがあります。

    • FloatingActionButtonLocation.endFloat: デフォルト設定。画面の右下に配置されます。
    • FloatingActionButtonLocation.centerFloat: 画面の中央下に配置されます。
    • FloatingActionButtonLocation.miniStartTop: 画面の左上に小さなサイズで配置されます。
Scaffold(
  floatingActionButton: FloatingActionButton(
    onPressed: () {
      // フローティングアクションの処理
    },
    child: Icon(Icons.add),
  ),
  floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
  // 他のウィジェットを含む
)
  • persistentFooterButtons
    画面の下部に固定されるボタン(コンテンツとは独立して表示されるアクションボタン)を指定します。
Scaffold(
  persistentFooterButtons: <Widget>[
    ElevatedButton(
      onPressed: () {
        // ボタンの処理
      },
      child: Text('ボタン1'),
    ),
    ElevatedButton(
      onPressed: () {
        // ボタンの処理
      },
      child: Text('ボタン2'),
    ),
  ],
  // 他のウィジェットを含む
)
  • backgroundColor
    Scaffoldの背景色を設定します。通常はColorsクラスの色を指定しますが、任意のColorオブジェクトを使用することもできます。
Scaffold(
  backgroundColor: Colors.grey[200],
  // 他のウィジェットを含む
)
  • resizeToAvoidBottomInset
    キーボードが表示された際の画面のリサイズを制御します。trueに設定すると、キーボードが表示されたときにコンテンツが自動的にスクロールして隠れないようになります。
Scaffold(
  resizeToAvoidBottomInset: false, // スクロールなし
  // 他のウィジェットを含む
)

  • extendBody
    bodyコンテンツを画面の下部まで拡張するかどうかを制御します。trueに設定すると、背景色やデザインがbodyまで広がり、下部ナビゲーションバーを含めた全体の高さになります。
Scaffold(
  extendBody: true,
  // 他のウィジェットを含む
)

  • extendBodyBehindAppBar
    appBarの下にコンテンツを表示するかどうかを制御します。trueに設定すると、appBarの下にbodyコンテンツが表示され、appBarの背後に配置されます。
Scaffold(
  extendBodyBehindAppBar: true,
  // 他のウィジェットを含む
)

Scaffoldサンプルコード

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyScaffoldApp(),
    );
  }
}

class MyScaffoldApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.search),
            onPressed: () {
              // 検索アクションの処理
            },
          ),
        ],
      ),
      body: Center(
        child: Text('Hello, World!'),
      ),
      drawer: Drawer(
        child: ListView(
          children: <Widget>[
            ListTile(
              title: Text('メニュー1'),
              onTap: () {
                // メニュー1の処理
              },
            ),
            ListTile(
              title: Text('メニュー2'),
              onTap: () {
                // メニュー2の処理
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // フローティングアクションの処理
        },
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
      persistentFooterButtons: <Widget>[
        ElevatedButton(
          onPressed: () {
            // ボタン1の処理
          },
          child: Text('ボタン1'),
        ),
        ElevatedButton(
          onPressed: () {
            // ボタン2の処理
          },
          child: Text('ボタン2'),
        ),
      ],
      backgroundColor: Colors.grey[200],
      resizeToAvoidBottomInset: true,
      extendBody: true,
      extendBodyBehindAppBar: false,
    );
  }
}

InheritedWidget

ウィジェットツリー内でデータを共有するための仕組みです。親ウィジェットから子ウィジェットにデータを渡す際に使用します。データをInheritedWidgetに持たせることで、依存関係がInheritedWidgetの下にあるWidgetならどこからでもデータを参照できるようになります。
ProviderパッケージRiverpodパッケージの普及によりInheritedWidgetを使用する機会はほとんど無くなってきていますが、InheritedWidgetの仕組みを理解することでProviderパッケージやRiverpodパッケージへの理解を深めることができます。

InheritedWidgetを使用したカウンタアプリ
import 'package:flutter/material.dart';

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

// カウンターの状態を提供するカスタムInheritedWidget
class CounterProvider extends InheritedWidget {
  final int counter; // カウンターの値
  final Function() increment; // カウンターを増やす関数

  const CounterProvider({
    super.key,
    required this.counter, // 初期カウンターの値
    required this.increment, // カウンターを増やす関数
    required Widget child, // 子ウィジェット
  }) : super(child: child);

  // InheritedWidgetを使ってカウンターの状態を取得するためのメソッド
  static CounterProvider? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CounterProvider>();
  }

  @override
  bool updateShouldNotify(covariant InheritedWidget oldWidget) {
    return false; // このメソッドは更新通知の制御に使われますが、この例では常にfalseを返しています
  }
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: CounterApp(),
    );
  }
}

class CounterApp extends StatefulWidget {
  const CounterApp({super.key});

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

class CounterAppState extends State<CounterApp> {
  int _counter = 0; // カウンターの初期値

  // カウンターを増やす関数
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return CounterProvider(
      counter: _counter, // カウンターの初期値を設定
      increment: _incrementCounter, // カウンターを増やす関数
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Counter App'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'Count:',
                style: TextStyle(fontSize: 20.0),
              ),
              Builder(
                builder: (context) {
                  final counterProvider = CounterProvider.of(context);
                  return Text(
                    '${counterProvider?.counter}', // カウンターの値を表示
                    style: const TextStyle(fontSize: 40.0),
                  );
                },
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _incrementCounter,
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}

StatelessWidget

状態を持たないウィジェットです。一度作成されたらその内容や見た目が変更されないウィジェットになりますので、通常、静的なコンテンツを表示するために使用されます。ウィジェットツリー内での再構築の必要がないため、効率的に動作します。

StatelessWidgetのサンプルコード

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hello Flutter Example',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Hello Flutter Example'),
        ),
        body: Center(
          // Stateless Widgetを呼び出す
          child: HelloFlutter(),
        ),
      ),
    );
  }
}

class HelloFlutter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(
      'Hello, Flutter!',
      style: TextStyle(fontSize: 24),
    );
  }
}

StatefulWidget

状態を持つウィジェットです。状態(State)は、ウィジェットが再描画されるときに変更することができます。ユーザー入力や時間の経過に応じて画面の情報を変更する際などに使用されます。

StatefulWidget不変であるWidgetを継承しているので、StatefulWidget自体は不変である必要があります。ではなぜStatefulWidgetが状態を持つウィジェットなのか? その理由はStateです。State可変の要素を持たせています。
Flutter SDKはStatefulWidget何度も再作成することができ、それに対しStateは1度だけ作成されます。そして、再作成されたStatefulWidgetは既に作成されているStateを参照することで、Widgetの再作成(画面の描画)を行うことができます。

StatefulWidgetのサンプルコード

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Counter App Example',
      home: CounterApp(),
    );
  }
}

class CounterApp extends StatefulWidget {
  @override
  _CounterAppState createState() => _CounterAppState();
}

class _CounterAppState extends State<CounterApp> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Counter Value:',
              style: TextStyle(fontSize: 20),
            ),
            Text(
              '$_counter',
              style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Material Widgets

FlutterのデザインライブラリであるMaterial Designに基づいて設計されたウィジェットのセットです。Material Designは、Googleが提供するデザインガイドラインで、アプリケーションの外観と動作を構築するのに使用されます。

  • RaisedButton
    タップすると反応するデザインで、ユーザーアクションを促します。

  • TextField
    ユーザーがテキストを入力できるウィジェットで、バリデーションやテキスト操作に対応します。

  • Card
    情報を整理して表示し、視覚的な階層を作成するのに使用されます。

  • AppBar
    アプリケーションの上部にタイトルやアクションボタンを表示し、ナビゲーションメニューを提供します。

  • ListView
    スクロール可能なリストを表示し、大量のデータを効果的に表示できます。

  • SnackBar
    一時的なメッセージや通知を表示するためのウィジェットです。

  • BottomNavigationBar
    アプリケーションの下部にナビゲーションメニューを提供し、異なる画面間を移動できます。

Cupertino Widgets

iOSのデザインガイドラインに従ったFlutterのウィジェットの一部で、iOSアプリケーションを開発する際、iOSのネイティブな外観と動作を構築するために使用されます。

  • CupertinoButton
    タップすると反応するデザインで、iOSアプリケーションに一般的に使用されます。

  • CupertinoTextField
    テキスト入力フィールド。iOSのテキスト入力フィールドの外観と動作を提供します。

  • CupertinoNavigationBar
    アプリケーションの上部にタイトルやアクションボタンを表示し、iOSアプリケーションに一般的に使用されます。

  • CupertinoAlertDialog
    メッセージやアクションボタンを含むアラートを表示します。iOSアプリケーションに一般的に使用されます。

  • CupertinoPicker
    ドロップダウンリストや選択ウィジェットとして使用され、iOSアプリケーションに一般的に使用されます。

Responsive Widgetとは

Responsive Widgetとは異なる画面サイズやデバイスに対応したウィジェット(コンポーネント)のことです。Flutterにおいて、Responsive Widgetを作成するためには、以下のようなアプローチがあります。

MediaQueryを使用する

MediaQueryクラスは、デバイスの画面サイズ、方向、ピクセル比率などの情報にアクセスするために使用されます。これを使用して、画面幅に基づいて異なるウィジェットを表示するなどの条件分岐を行うことができます。

final double screenWidth = MediaQuery.of(context).size.width;

if (screenWidth > 600) {
  // 大画面向けのウィジェットを表示
  return DesktopWidget();
} else {
  // スマートフォン向けのウィジェットを表示
  return MobileWidget();
}

LayoutBuilderを使用する

LayoutBuilderウィジェットは、親ウィジェットのサイズに基づいて子ウィジェットを構築するのに使用されます。親ウィジェットのサイズに合わせて子ウィジェットの配置やサイズを動的に調整できるため、ウィンドウの幅に応じて列の数を調整する際などに使用します。

LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth > 600) {
      // 大画面向けの表示
      return Row(
        children: <Widget>[
          Expanded(child: Widget1()),
          Expanded(child: Widget2()),
        ],
      );
    } else {
      // スマートフォン向けの表示
      return Column(
        children: <Widget>[
          Widget1(),
          Widget2(),
        ],
      );
    }
  },
)

Responsiveパッケージを使用する

Flutterには、レスポンシブデザインを簡素化するためのパッケージが多数存在します。例えば、responsive_frameworkflutter_responsiveなどのパッケージを使用すると、簡単にレスポンシブなレイアウトを作成できます。プロジェクトや使用感などご自身に合ったパッケージを選択してみてください。

FlexやExpandedを使用する

FlexウィジェットExpandedウィジェットを活用することで、ウィジェットのサイズや配置を調整できます。これらのウィジェットを使用することで、利用可能なスペースを最大限に活用することができます。
FlexibleとExpandedの主な違いは、サイズ調整の方法にあります。Flexibleはウィジェットのサイズを柔軟に調整できるのに対して、Expandedは利用可能な空間をすべて埋めるようにウィジェットを拡張します。

参考資料

  1. コンポーネント
    単体では使用せず、他のプログラムから呼び出されたり連結されたりして使用されるプログラム部品のこと
    こちらにわかりやすい記事があったので、是非読んでみてください。

  2. プロパティ
    取り扱う対象(オブジェクト)の持つ設定や状態、属性などの情報のことです。
    こちらにわかりやすい記事があったので、是非読んでみてください。

  3. アスペクト比
    アスペクト比とは、画像や動画等の映像の縦横比のことを指します。一般的にワイド(16:9)とスタンダード(4:3)の2つが基本的なアスペクト比とされています。
    https://gimo.jp/glossary/details/aspect_ratio.html

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?