Flutter

Flutterで水平方向にスクロールできるタブバーを実装する手順


Photo by Thought Catalog on Unsplash

はじめに

ニュースアプリなどでアプリのトップバーにタブを表示してかつそのタブをスクロールできるように実装されているレイアウトを見ることがあると思います。例えばカテゴリ毎にタブが別れている場合などです。この記事では、水平方向にスクロールできるタブバーを実装する手順をまとめます。

できるようになること

以下のGIF画像のように、スクロール可能なタブバーを実装します。また、アクティブでないタブの文字を薄くして表示します。

このデモのコードは以下のGitHubにあげてあります。

参考文献

以下の公式ドキュメントのコードを参考にさせて頂きました。

Working with Tabs

Working with tabs is a common pattern in apps following the Material Designguidelines. Flutter includes a convenient way to create tab layouts as part ofthe [material library]({{site.api}}/flutter/material/material-library.html).## Directions 1. Create a `TabController` 2. Create the tabs 3. Create content for each tab## 1. Create a `TabController`In order for tabs to…

前提と環境

以下の通りです。

  • Flutter 1.5.4-hotfix.2
  • Dart 2.3.0

スクロールできるタブバーのシンプルな例

以下が冒頭に載せたGIF画像のコードになります。基本的には参考文献の公式ドキュメントのコードになりますが、isScrollableによって水平方向にスクロール可能にし、unselectedLabelColorでアクティブでないタブの文字色を半透明にしています。これらオプションの内容は後述します。

lib/main.dartimport 'package:flutter/material.dart';

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

class TabBarDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        // タブの数
        length: 7,
        child: Scaffold(
          appBar: AppBar(
            bottom: TabBar(
              // タブのオプション
              isScrollable: true,
              unselectedLabelColor: Colors.white.withOpacity(0.3),
              unselectedLabelStyle: TextStyle(fontSize: 12.0),
              labelColor: Colors.yellowAccent,
              labelStyle: TextStyle(fontSize: 16.0),
              indicatorColor: Colors.white,
              indicatorWeight: 2.0,
              // タブに表示する内容
              tabs: [
                      Tab(
                        child: Text('Top'),
                      ),
                      Tab(
                        child: Text('Business'),
                      ),
                      Tab(
                        child: Text('Technology'),
                      ),
                      Tab(
                        child: Text('Finance'),
                      ),
                      Tab(
                        child: Text('Food'),
                      ),
                      Tab(
                        child: Text('Economic'),
                      ),
                      Tab(
                        child: Text('Game'),
                      )
              ],
            ),
            title: Text('Tabs Demo'),
          ),
          body: TabBarView(
            // 各タブの内容
            children: [
              Icon(Icons.directions_car),
              Icon(Icons.directions_transit),
              Icon(Icons.directions_bike),
              Icon(Icons.directions_car),
              Icon(Icons.directions_transit),
              Icon(Icons.directions_bike),
              Icon(Icons.directions_car)
            ],
          ),
        ),
      ),
    );
  }
}

上記コードの中で使用しているタブバーの見た目に関わるオプションは以下になります。

オプション名内容
isScrollabletrueでタブバーの水平方向へのスクロールを可能にします。
unselectedLabelColorタブバーのアクティブでない(選択中でない)テキストの色を指定します。上記コードでは、アクティブでないタブバーの文字色を半透明の白色に設定するためにColors.white.withOpacity(0.3)を与えています。
unselectedLabelStyleタブバーのアクティブでない(選択中でない)テキストのスタイルを指定します。ここで指定できるスタイルは、TextStyle classに記載されています。
labelColorタブバーのアクティブである(選択中である)テキストの色を指定します。
labelStyleタブバーのアクティブである(選択中である)テキストのスタイルを指定します。ここで指定できるスタイルは、TextStyle classに記載されています。
indicatorColorタブバーのアクティブであるテキスト下に表示されるインディケーター(冒頭のGIFのデモの場合、白色のバー)の色を指定します。
indicatorWeightタブバーのアクティブであるテキスト下に表示されるインディケーターの太さを指定します。デフォルトでは2.0で大きくするほど太くなります。

その他の全てのオプションは以下の公式ドキュメントに記載されています。

TabBar class

A material design widget that displays a horizontal row of tabs.

各タブの内容を別ファイルから読み込みたい場合

すでに載せたコードでは各タブの内容がアイコンしかない例でしたが、同じmain.dartに定義したウィジェットを読み込んだり、以下のように別ファイルからウィジェットを読み込むことももちろんできます。以下では、例えばプロジェクト名がtopbarmain.dartと同じディレクトリにfirsttab.dartというファイルがある前提です。

lib/main.dartimport 'package:topbar/firsttab.dart';
(...途中省略...)
         body: TabBarView(
            // 各タブの内容
            children: [
              // Icon(Icons.directions_car),
              new FirstTab('test'), // 別ファイルで定義しているウィジェットを使用する。
              Icon(Icons.directions_transit),
              Icon(Icons.directions_bike),
              Icon(Icons.directions_car),
              Icon(Icons.directions_transit),
              Icon(Icons.directions_bike),
              Icon(Icons.directions_car)
            ],
          ),
(...以下省略...) 

firsttab.dartは例えば以下のように定義します。以下ではcategoryNameという適当な文字列を親ウィジェットから受け取れるようにしていますが、もちろんなくてもOKです。

lib/firsttab.dartimport 'package:flutter/material.dart';

class FirstTab extends StatefulWidget {
  FirstTab(this.categoryName);
  final String categoryName;

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

class _FirstTabState extends State<FirstTab> {
  
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      backgroundColor: Colors.blue,
      body: new Container(
        child: new Center(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new Icon(
                Icons.library_books,
                size: 50.0,
                color: Colors.white,
              ),
              new Text(
                widget.categoryName,
                style: new TextStyle(color: Colors.white),
              )
            ],
          ),
        ),
      ),
    );
  }
}

まとめ

Flutterではアプリでよく見るような機能が大体デフォルトで揃っており便利です。

SPONSORED LINK

コメントを残す

メールアドレスが公開されることはありません。