タグやフィルターなどの細々とした情報を簡単に追加削除する Chip を Wrap 内で使って折り返す方法

Material Design ではタグ、フィルター、あるいはメールの宛先などの個別のデータなどは Chip というコンポーネントで受け持つことになっています。

Flutter の Material Components にも Chip ウィジェットがあって、ここで実装例を示すように簡単に使うことができます。 追加や削除はとても簡単です。ただ、複数のチップを並べるために、並び順に折り返したりする必要があって、それには一工夫必要です。

ここでは、Wrap というウィジェットと組み合わせることで、Chip が増えてきたときに二列以上に折り返して並べています。

基本的に Wrap の children プロパティに Chip のリストを渡せばよいだけです。 それから並べる向きや間隔に関するプロパティを設定します。

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  debugPaintSizeEnabled = false;
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyApp(),
    ),
  );
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _State();
  }
}

class _State extends State<MyApp> {
  var _textFieldFocusNode;
  var _inputController = TextEditingController();
  var _chipList = List<Chip>();
  var _keyNumber = 0;

  @override
  void initState() {
    _textFieldFocusNode = FocusNode();
    super.initState();
  }

  @override
  void dispose() {
    _textFieldFocusNode.dispose();
    super.dispose();
  }

  void _onSubmitted(String text) {
    setState(() {
      _inputController.text = '';
      _addChip(text);
      FocusScope.of(context).requestFocus(_textFieldFocusNode);
    });
  }

  void _addChip(String text) {
    var chipKey = Key('chip_key_$_keyNumber');
    _keyNumber++;

    _chipList.add(
      Chip(
        key: chipKey,
        label: Text(text),
        onDeleted: () => _deleteChip(chipKey),
      ),
    );
  }

  void _deleteChip(Key chipKey) {
    setState(() => _chipList.removeWhere((Widget w) => w.key == chipKey));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Chip Test'),
      ),
      body: Container(
        padding: EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            TextField(
              focusNode: _textFieldFocusNode,
              autofocus: true,
              controller: _inputController,
              decoration: InputDecoration(
                hintText: 'Enter Tag...',
              ),
              onSubmitted: _onSubmitted,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Expanded(
                  child: Wrap(
                    alignment: WrapAlignment.start,
                    spacing: 8.0,
                    runSpacing: 0.0,
                    direction: Axis.horizontal,
                    children: _chipList,
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

少しコードが増えてしまっていますが、テキストフィールドにフォーカスを移したり、Chip のリストに Chip を追加したり削除したりする部分が大半です。

Wrap ウィジェットに関して言えば、children プロパティに Chip のリストを渡しているだけです。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Flutter 入門