【Flutter】Dividerで項目を分ける

対象者

  • Flutterでアプリ開発を始めたばかりで、基本的なウィジェットの使い方を学びたい初心者
  • 経験豊富な開発者でも、Flutterの特定のウィジェット、特にDividerやVerticalDividerの使用法について詳しく知りたい
  • UI/UXに重視し、アプリの見た目を改善するための具体的な方法や技術を探しているデザイナー

はじめに

Dividerというのは、日本語で「分割器」または「区切り」という意味です。プログラムの世界では一般的に「異なる要素やセクションを視覚的に分ける」ことを示します。
Flutterにおいては、視覚的に要素間を分けるウィジェットです。そのため、UI上で要素の区切りを明確に示すことができます。
実際のアプリとしては、リストビューの各アイテムや設定画面の各項目間などに、視覚的な区切り線としてDividerを用いるというようなケースにおいて、ユーザーが情報を認識しやすくするというような機能を実現することができます。

Dividerについて

FlutterはGoogleが開発したモバイルアプリケーションの開発フレームワークで、その中にある基本的なウィジェットの一つがDividerです。Dividerは主にユーザインターフェース(UI)の要素を視覚的に分けるために使われます。それによってUIは整理され、ユーザーにとって理解しやすくなるため、Flutterアプリのユーザビリティ向上に大いに役立ちます。

Dividerウィジェットの基本的な使用法は非常にシンプルです。Dividerは基本的に水平線を描くためのウィジェットで、ウィジェット間の空間を明確に分ける役割を果たします。

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

上記のコードは、Dividerを使って3つのテキストウィジェットを分ける簡単な例です。結果的に、’Item 1′, ‘Item 2’, ‘Item 3’の各項目はそれぞれ別の行に表示され、その間には水平線が描かれます。

ただし、Dividerウィジェットはカスタマイズが可能で、より洗練されたUIを作成するために使われることもあります。カスタマイズ可能なプロパティには、高さ(space above and below the divider)、色、厚さ、インデント(左側のスペース)、エンドインデント(右側のスペース)などがあります。以下にその一例を示します。

Divider(
  color: Colors.green,
  height: 20,
  thickness: 5,
  indent: 20,
  endIndent: 0,
)

このように、FlutterのDividerはその単純さと同時に強力なカスタマイズ能力を持つため、アプリのUIを効果的に設計する際に重要な役割を果たします。

プラクティカルなDividerの使用例

ListViewやRowなど、複数のウィジェットをまとめるためのレイアウトウィジェットとDividerを組み合わせることで、項目間の明確な分割線を提供し、ユーザビリティを向上させることができます。今回は、それぞれの使用例を紹介します。

RowにおけるDividerの使用

一方、Rowは一連のウィジェットを水平に並べるレイアウトウィジェットです。Dividerは基本的に水平線を描くウィジェットですが、Row内で使うことで垂直線として機能し、項目間を視覚的に区別することができます。その際にはVerticalDividerを使用します。以下にその実装例を示します。

Row(
  children: <Widget>[
    Text('Item 1'),
    VerticalDivider(),
    Text('Item 2'),
    VerticalDivider(),
    Text('Item 3'),
  ],
)

このコードは、3つのテキストウィジェットを水平に配置し、各項目間に垂直のDividerを挿入するものです。こうすることで、水平方向に配置された各項目が明確に区別され、ユーザにとってわかりやすいUIが実現します。

ListViewにおけるDividerの使用

ListView.separated

ListViewは、一連の項目を垂直に並べるためのウィジェットです。特にリスト表示に適しており、Dividerを使用することでリスト内の各項目を明確に区別できます。以下にその実装例を示します。

ListView.separated(
  itemCount: 10,
  separatorBuilder: (BuildContext context, int index) => Divider(
    color: Colors.grey,
        thickness: 2,
  ),
  itemBuilder: (BuildContext context, int index) {
        return ListTile(
          title: Text('Item ${index + 1}'),
        );
  },
)

このコードは、10つの項目を含むListViewを作成し、各項目間にDividerを挿入するようseparatorBuilderで指定しています。

ListTile.divideTiles

こちらはDividerとは少し異なりますが、ListTile.divideTiles を使うことで自動的に線を入れることが可能です。

ListView(
  children: ListTile.divideTiles(
    context: context,
    tiles: [
      ListTile(title: Text('Item 1')),
      ListTile(title: Text('Item 2')),
      ListTile(title: Text('Item 3')),
    ],
  ).toList(),
)

このコードは、3つの項目を含むListViewを作成し、各項目間にDividerを自動的に挿入するものです。各項目はそのままではなく、ListTileというウィジェットを使用している点に注意してください。これにより、DividerはListTileの間に挿入され、見栄えの良いリストが作成されます。

以上のように、DividerはListViewやRowと組み合わせることで、項目間の明確な分割線を提供し、ユーザビリティを大幅に向上させることが可能です。これらの使用例を試し、効果的なUIデザインの一部として活用してみてください。

Q&A

Q1: Dividerとはなんですか?

A: DividerはFlutterのウィジェットで、視覚的にセクションを分けるために使われます。その名の通り、Dividerは親要素の利用可能な幅全体にわたる水平線を描画します。これにより、UI内の異なる要素やセクションを分けて表示することができます。

Q2: Dividerの厚みと色をカスタマイズするにはどうすれば良いですか?

A: Dividerの厚みと色をカスタマイズするには、それぞれ「thickness」と「color」プロパティを使用します。これらのプロパティに適切な値を設定することで、Dividerの見た目を自由にカスタマイズすることが可能です。例えば、Dividerの厚みを4ピクセル、色を赤に設定したい場合、次のように記述します。

Divider(
  color: Colors.red,
  thickness: 4,
)

Q3: FlutterでDividerが表示されないのはなぜですか?

A: Flutterでは、Dividerウィジェットは親ウィジェットの利用可能な空間を基準に表示されます。そのため、親ウィジェットの空間が不足していたり、親ウィジェットがDividerのサイズを正しく制約できない場合、Dividerが表示されないことがあります。これを解決するためには、Dividerを包含するウィジェット(ExpandedやSizedBox)を使用して親ウィジェットの利用可能な領域全体を使ってDividerを伸ばすと良いでしょう。

まとめ

今日のブログを通じて、あなたはFlutterのDividerウィジェットの基本的な使い方やカスタマイズ方法を学びました。Dividerとその垂直バージョンであるVerticalDividerは、アプリのユーザビリティを向上させるための重要なツールと理解されました。それは、ユーザインターフェースの要素間を視覚的に分け、整理されたUIを提供します。

Dividerの基本的な使い方は非常にシンプルで、線の色や厚み、高さ、左右のインデントをカスタマイズすることができることを理解しました。また、RowとVerticalDividerを組み合わせて垂直線を作り出す方法、そして、ListViewとDividerを組み合わせて各項目間を視覚的に区別する方法を習得しました。これらの知識を活用して、あなたのFlutterアプリのUIを更に改善することができるでしょう。

このブログではDividerの重要性とその使用方法を詳しく解説しましたが、実際に自分でコードを書いてみることで理解を深めることができるでしょう。実践的な学習を通じて、FlutterのUIデザインのスキルをさらに磨いていきましょう。

参考

ソース(main.dartにコピペして動作確認用)

import 'package:flutter/material.dart';

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

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

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

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

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: <Widget>[
          Text('Item 1'),
          Divider(),
          Text('Item 2'),
          Divider(
            color: Colors.green,
            height: 32,
            thickness: 16,
            indent: 8,
            endIndent: 64,
          ),
          Text('Item 3'),
          SizedBox(
            height: 32,
            child: Row(
              children: <Widget>[
                Text('Item 1'),
                VerticalDivider(thickness: 16, color: Colors.green, width: 8),
                Text('Item 2'),
                VerticalDivider(),
                Text('Item 3'),
              ],
            ),
          ),
          Expanded(
            child: Row(
              children: <Widget>[
                Text('Item 1'),
                VerticalDivider(thickness: 16, color: Colors.green, width: 8),
                Text('Item 2'),
                VerticalDivider(),
                Text('Item 3'),
              ],
            ),
          ),
          Expanded(
            child: ListView(
              children: ListTile.divideTiles(
                context: context,
                tiles: [
                  ListTile(title: Text('Item 1')),
                  ListTile(title: Text('Item 2')),
                  ListTile(title: Text('Item 3')),
                ],
              ).toList(),
            ),
          ),
          ListTile(title: Text('Item 4')),
          ListTile(title: Text('Item 5')),
          Expanded(
            child: ListView.separated(
              itemCount: 10,
              separatorBuilder: (BuildContext context, int index) => Divider(
                color: Colors.grey,
                thickness: 2,
              ),
              itemBuilder: (BuildContext context, int index) {
                return ListTile(
                  title: Text('Item ${index + 1}'),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}