flutter&firebase でWEBサービス ハッシュタグをchipsで実装

ハッシュタグの実装方法

flutterではChipsでハッシュタグの実装を行います。

以下のサイトを参考にさせて頂きました。

https://take424.dev/2021/06/08/flutter%E3%81%A7%E5%90%84%E7%A8%AEchip%E3%82%A6%E3%82%A3%E3%82%B8%E3%82%A7%E3%83%83%E3%83%88%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B/

完成イメージ

作成したハッシュタグの実装画面です。

完成後の動作です。

ソースコード

上記の完成イメージになるWidgetです。child要素にtagChipsを設定しています。

Card(
color: Colors.white,
child: Padding(
padding: EdgeInsets.all(8.0),
child: tagChips,
)),
Card( color: Colors.white, child: Padding( padding: EdgeInsets.all(8.0), child: tagChips, )),
Card(
    color: Colors.white,
    child: Padding(
      padding: EdgeInsets.all(8.0),
      child: tagChips,
    )),

tagChips

完成したハッシュタグ用のwidgetです。StatelessWidgetで作成しています。

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:provider/provider.dart';
import 'package:stockcodes/model/codeModel.dart';
class TagChips extends StatelessWidget {
late FocusNode _textFieldFocusNode;
late TextEditingController _inputController;
late List<String> _tagStrings;
List<Chip> _chipList = [];
int _keyNumber = 0;
late bool _editflag;
bool _firstBuild = true;
TagChips(List<String>? tagStrings, bool editflag) {
this._tagStrings = tagStrings!;
this._editflag = editflag;
this._textFieldFocusNode = FocusNode();
this._inputController = TextEditingController();
_inputController.text = '';
}
List<String> get tags {
_tagStrings = [];
_chipList.forEach((chip) {
Text text = chip.label as Text;
_tagStrings.add(text.data!);
});
return _tagStrings;
}
Key _getKey() {
Key chipKey = Key('chip_key_$_keyNumber');
_keyNumber++;
return chipKey;
}
@override
Widget build(BuildContext context) {
final CodeModel codeModel = Provider.of<CodeModel>(context);
//初回だけ実行
if (_firstBuild) {
this._tagStrings.forEach((tagstring) {
Key keystr = _getKey();
_chipList.add(Chip(
key: keystr,
backgroundColor: Colors.blue,
labelStyle: TextStyle(
color: Colors.white,
),
label: Text(tagstring),
onDeleted: () {
if (_editflag) {
_chipList.removeWhere((Widget w) => w.key == keystr);
codeModel.update();
}
},
));
});
_firstBuild = false;
}
return Container(
padding: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
TextField(
focusNode: _textFieldFocusNode,
enabled: _editflag,
controller: _inputController,
decoration: InputDecoration(
hintText: 'タグを追加...',
),
onSubmitted: (String text) {
_inputController.text = '';
Key keystr = _getKey();
_chipList.add(
Chip(
key: keystr,
label: Text(text),
backgroundColor: Colors.blue,
labelStyle: TextStyle(
color: Colors.white,
),
onDeleted: () {
_chipList.removeWhere((Widget w) => w.key == keystr);
codeModel.update();
},
),
);
FocusScope.of(context).requestFocus(_textFieldFocusNode);
codeModel.update();
},
),
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,
),
),
],
),
],
),
);
}
}
import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:provider/provider.dart'; import 'package:stockcodes/model/codeModel.dart'; class TagChips extends StatelessWidget { late FocusNode _textFieldFocusNode; late TextEditingController _inputController; late List<String> _tagStrings; List<Chip> _chipList = []; int _keyNumber = 0; late bool _editflag; bool _firstBuild = true; TagChips(List<String>? tagStrings, bool editflag) { this._tagStrings = tagStrings!; this._editflag = editflag; this._textFieldFocusNode = FocusNode(); this._inputController = TextEditingController(); _inputController.text = ''; } List<String> get tags { _tagStrings = []; _chipList.forEach((chip) { Text text = chip.label as Text; _tagStrings.add(text.data!); }); return _tagStrings; } Key _getKey() { Key chipKey = Key('chip_key_$_keyNumber'); _keyNumber++; return chipKey; } @override Widget build(BuildContext context) { final CodeModel codeModel = Provider.of<CodeModel>(context); //初回だけ実行 if (_firstBuild) { this._tagStrings.forEach((tagstring) { Key keystr = _getKey(); _chipList.add(Chip( key: keystr, backgroundColor: Colors.blue, labelStyle: TextStyle( color: Colors.white, ), label: Text(tagstring), onDeleted: () { if (_editflag) { _chipList.removeWhere((Widget w) => w.key == keystr); codeModel.update(); } }, )); }); _firstBuild = false; } return Container( padding: EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ TextField( focusNode: _textFieldFocusNode, enabled: _editflag, controller: _inputController, decoration: InputDecoration( hintText: 'タグを追加...', ), onSubmitted: (String text) { _inputController.text = ''; Key keystr = _getKey(); _chipList.add( Chip( key: keystr, label: Text(text), backgroundColor: Colors.blue, labelStyle: TextStyle( color: Colors.white, ), onDeleted: () { _chipList.removeWhere((Widget w) => w.key == keystr); codeModel.update(); }, ), ); FocusScope.of(context).requestFocus(_textFieldFocusNode); codeModel.update(); }, ), 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, ), ), ], ), ], ), ); } }
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:provider/provider.dart';
import 'package:stockcodes/model/codeModel.dart';

class TagChips extends StatelessWidget {
  late FocusNode _textFieldFocusNode;
  late TextEditingController _inputController;
  late List<String> _tagStrings;
  List<Chip> _chipList = [];
  int _keyNumber = 0;
  late bool _editflag;
  bool _firstBuild = true;

  TagChips(List<String>? tagStrings, bool editflag) {
    this._tagStrings = tagStrings!;
    this._editflag = editflag;
    this._textFieldFocusNode = FocusNode();
    this._inputController = TextEditingController();
    _inputController.text = '';
  }

  List<String> get tags {
    _tagStrings = [];
    _chipList.forEach((chip) {
      Text text = chip.label as Text;
      _tagStrings.add(text.data!);
    });
    return _tagStrings;
  }

  Key _getKey() {
    Key chipKey = Key('chip_key_$_keyNumber');
    _keyNumber++;
    return chipKey;
  }

  @override
  Widget build(BuildContext context) {
    final CodeModel codeModel = Provider.of<CodeModel>(context);

    //初回だけ実行
    if (_firstBuild) {
      this._tagStrings.forEach((tagstring) {
        Key keystr = _getKey();
        _chipList.add(Chip(
          key: keystr,
          backgroundColor: Colors.blue,
          labelStyle: TextStyle(
            color: Colors.white,
          ),
          label: Text(tagstring),
          onDeleted: () {
            if (_editflag) {
              _chipList.removeWhere((Widget w) => w.key == keystr);
              codeModel.update();
            }
          },
        ));
      });
      _firstBuild = false;
    }

    return Container(
      padding: EdgeInsets.all(16.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: <Widget>[
          TextField(
            focusNode: _textFieldFocusNode,
            enabled: _editflag,
            controller: _inputController,
            decoration: InputDecoration(
              hintText: 'タグを追加...',
            ),
            onSubmitted: (String text) {
              _inputController.text = '';
              Key keystr = _getKey();
              _chipList.add(
                Chip(
                  key: keystr,
                  label: Text(text),
                  backgroundColor: Colors.blue,
                  labelStyle: TextStyle(
                    color: Colors.white,
                  ),
                  onDeleted: () {
                    _chipList.removeWhere((Widget w) => w.key == keystr);
                    codeModel.update();
                  },
                ),
              );
              FocusScope.of(context).requestFocus(_textFieldFocusNode);
              codeModel.update();
            },
          ),
          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,
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

ハマったところ

初回だけ初期値設定

statelessで作ったためか、画面の再描画によりchipsのデータが消えたりする挙動が発生しました。そのため初回だけ値を設定する処理を追加しています。

//初回だけ実行
if (_firstBuild) {
this._tagStrings.forEach((tagstring) {
Key keystr = _getKey();
_chipList.add(Chip(
key: keystr,
backgroundColor: Colors.blue,
labelStyle: TextStyle(
color: Colors.white,
),
label: Text(tagstring),
onDeleted: () {
if (_editflag) {
_chipList.removeWhere((Widget w) => w.key == keystr);
codeModel.update();
}
},
));
});
_firstBuild = false;
}
//初回だけ実行 if (_firstBuild) { this._tagStrings.forEach((tagstring) { Key keystr = _getKey(); _chipList.add(Chip( key: keystr, backgroundColor: Colors.blue, labelStyle: TextStyle( color: Colors.white, ), label: Text(tagstring), onDeleted: () { if (_editflag) { _chipList.removeWhere((Widget w) => w.key == keystr); codeModel.update(); } }, )); }); _firstBuild = false; }
    //初回だけ実行
    if (_firstBuild) {
      this._tagStrings.forEach((tagstring) {
        Key keystr = _getKey();
        _chipList.add(Chip(
          key: keystr,
          backgroundColor: Colors.blue,
          labelStyle: TextStyle(
            color: Colors.white,
          ),
          label: Text(tagstring),
          onDeleted: () {
            if (_editflag) {
              _chipList.removeWhere((Widget w) => w.key == keystr);
              codeModel.update();
            }
          },
        ));
      });
      _firstBuild = false;
    }

値を返すための関数

chipsに設定した値を最後にリストで返却するのですが、どうやってchipsから値を取得してよいか分からずはまりました。以下のやり方でうまくいっています。

List<String> get tags {
_tagStrings = [];
_chipList.forEach((chip) {
Text text = chip.label as Text;
_tagStrings.add(text.data!);
});
return _tagStrings;
}
List<String> get tags { _tagStrings = []; _chipList.forEach((chip) { Text text = chip.label as Text; _tagStrings.add(text.data!); }); return _tagStrings; }
  List<String> get tags {
    _tagStrings = [];
    _chipList.forEach((chip) {
      Text text = chip.label as Text;
      _tagStrings.add(text.data!);
    });
    return _tagStrings;
  }

About: ken


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください