[Flutter]ChoiceChip、FilterChipなど、Chip系のWidgetの概要やユースケースの紹介と実装

Material Design でタグやフィルタなどを表現する時に使われるChipについて、Flutterではどのようなものがあるのかサンプルコードとともに紹介します。
2020.06.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ChoiceChipを使って選択肢を表示して任意のものをユーザーに選択させるUIが簡単に作れます。この記事ではChoiceChipを使って基本的な使い方を紹介しながら他のInputChipやFilterChipなどの概要やユースケースを紹介しつつ動くサンプルコードを提示します。

※Flutterを初めたばかりの人でもわかるようにsetStateとStatefulWidgetを使って状態の管理・更新を行います。Viewとロジックが密になってしまうデメリットはありますが、基本的なDartとFlutterのお作法を知っていれば簡単に理解できると思います。

また、一環してcodepenによる埋め込みを使っています。codepenの埋め込みはchromeでの閲覧を推奨します。 以前codepen側のセキュリティ強化施策により埋め込んだコンテンツが表示されない問題がありましたが問い合わせをして報告して修正してもらいましたのできちんと表示されていると思います。ご迷惑をおかけしました。

ChoiceChipの概要

複数の選択肢の中から1つの選択肢を表したい時に使用します。コンストラクタ引数に適宜値を渡すことにより関連する説明テキストやカテゴリを含めることができます。

ChoiceChipの基本的な使い方

以下のコードにコードを追加しながら実装していきます。中央にボタンが表示されているだけのUIです。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.deepPurple,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        child: Text('ボタン'),
        onPressed: () {},
      ),
    );
  }
}

ボタンをタップしたらChoiceChipを含むWidgetをアラート表示するだけの最低限の実装が以下になります。

See the Pen ChoceChipSample1 by Nobuyuki Tanabe (@nabeatsu) on CodePen.

次に複数のChopChoiceを表示して、かつ端っこで折り返して欲しいのでWrapを使います。複数ChopChoiceを表示して複数選択はできないものの一つ選択したら他の選択状態が解除されるようにします。

選択状態の有効化と無効化のロジックは単純でString型の変数を保持して選択したものを変数に代入します。選択状態を判定するロジックは変数に保持している文字列と同一であれば選択状態を有効にするだけです。setState内で代入をすれば最新のStateがwidget treeに反映されます。

See the Pen ChopChoiceSample2 by Nobuyuki Tanabe (@nabeatsu) on CodePen.

次に複数選択可能になるよう実装します。ここのロジックも単純でさきほどはString型の変数を保持していましたが、今回はList型の変数を保持するようにします。containsメソッドで変数の中に選択肢たChopChoiceのlabelのテキストが含まれていればListからその要素を削除、含まれていなければリストに追加します。setStateにより状態が反映されて複数選択ができるようになります。

See the Pen ChoiceChipSample3 by Nobuyuki Tanabe (@nabeatsu) on CodePen.

ここまで書いておいてなんですが、ChoiceChipを複数の選択肢から選択させるUIの実装には使用しないほうが良いと考えています。ドキュメントによると複数の選択肢から単一の選択肢を選ばせるUIに使用するとあります。

そして複数の選択肢から複数選ばせるUIを作るためのWidgetとしてFilterChipが提供されています。後ほど改めて紹介しますがFiliterChipを使って実装するほうが良いと思います。

カスタマイズ

ChoiceChipのconstructor引数は多いです。これを利用して様々なカスタマイズができます。

const ChoiceChip({
    Key key,
    this.avatar,
    @required this.label,
    this.labelStyle,
    this.labelPadding,
    this.onSelected,
    this.pressElevation,
    @required this.selected,
    this.selectedColor,
    this.disabledColor,
    this.tooltip,
    this.shape,
    this.clipBehavior = Clip.none,
    this.focusNode,
    this.autofocus = false,
    this.backgroundColor,
    this.padding,
    this.visualDensity,
    this.materialTapTargetSize,
    this.elevation,
    this.shadowColor,
    this.selectedShadowColor,
    this.avatarBorder = const CircleBorder(),
  }) : assert(selected != null),
       assert(label != null),
       assert(clipBehavior != null),
       assert(autofocus != null),
       assert(pressElevation == null || pressElevation >= 0.0),
       assert(elevation == null || elevation >= 0.0),
       super(key: key);

See the Pen ChoiceChipCustomizeSample1 by Nobuyuki Tanabe (@nabeatsu) on CodePen.

他の類似した命名のWidgetについて

ChoiceChipのドキュメントを読むと関連リンクとして他にもクラスが紹介されています。紹介されていたもののドキュメントへのリンクを張りつつ概要を紹介します。

Chip

チップは属性、テキスト、エンティティ、アクションを表すコンパクトな要素です。onDeleted コールバックを指定すると、チップに削除用のボタンが含まれるようになります。

ActionChip

関連するアクションをトリガーするオプションのセットです。ドキュメントによるとUI内で動的かつコンテキスト的に表示されるべきとあります。発火させてアクションを実行したり、進捗状況や確認を表示したりするためにタップすることができます。アクションを無効にすることはできません。ボタンは利用できない選択肢は通常、無効化されたコントロールとして表現されるのに対しActionChipは無効な時は表示されるべきでないとも書かれています。

InputChip

InputChipはエンティティや文などの複雑な情報をコンパクトに表現するのに使用するとあります。引数onSelectedに値を与えると選択可能に、onDeletedに値を与えると削除可能に、onPressedに値を与えることでボタンのように押せるようになります。labelや先頭と末尾にアイコンがセットできます。末尾はdeleteIconでここをタップするとonDeletedが呼び出されます。カスタマイズも自由度があります。

ほかのChip系のWidgetへの解説と異なり、他の要素と一緒に動作する旨が強調されていました。例としてWrap widgetの中、水平方向にスクロール可能なウィジェットの中などが例として紹介されています。

FilterChip

FilterChipは、タグや説明的な言葉を表すのに使われ、チェックボックスやスイッチの代わりにも使えます。コンパクトなエリアで明確に区別されたオプションを表示できることがメリットとして紹介されています。

次の節ではここで紹介した各Widgetを実装したサンプルを例示します。

他のWidgetをまとめて実装したサンプルコード

例によってcodepenです。クラス名ごとに区切ってあります。Chip class example2の下にあるChip widgetは右側のゴミ箱ボタンを押すと消せます。ActionChip classの下にあるActionChip widgetはタップするとsnackbarを表示します。あと説明が必要なのはFilterChip classの下にあるFilterChip Widgetですが複数選択できるようになっています。選択したものにはチェックマークがつきます。サンプルコードなので使用するプロパティは近くにあった方が良いかと思ってWidgetの定義の上で使用するプロパティを宣言してます。

See the Pen ChipsSample by Nobuyuki Tanabe (@nabeatsu) on CodePen.

実装の際に参考にしたドキュメント、動画

ドキュメントの他に参考にしたページを紹介します。

まとめ

最初はChoiceChipの記事を書くつもりでしたが、ドキュメントを読んでいく内にある程度まとめて紹介したほうが良いなと思ってこのような構成にしました。ドキュメントやソースコードを読みつつ記事を書きましたが誤りがあるかもしれません。なにかお気づきになられたらコメントかTwitterにてお知らせください。

最後まで読んでいただいてありがとうございました。