つてとのブログ

【Flutter/Dart開発】twitterのような#ハッシュタグ検索をしてみたい話(実践編)

 

こんにちは、エメラルドどハマり中おじさん

たちつてとです。

 

過去記事で

【Flutter/Dart開発】twitterのような#ハッシュタグ検索をしてみたい話(理屈編)

表題通りタグ検索の作るためのロジックを

考えてみたんですが。

 

実際に作ったで。という話を忘れてしまいそうで

悲しかったので記事にする次第です。

基本的に作戦は過去記事にある(はず...)。

 

大前提

以下にはソースを書いていくんですが

流石に全てを載せても仕方がないので

箇条書きで前提を書きます。

  • 雑学等を保存するメモアプリが主役
  • メモアプリにはオリジナルクラス「Memo」がある
  • 「Memo」には「#タグ」に相当するプロパティがある
  • 「#タグ」プロパティには、半角スペースを境に複数のタグを格納している

こんな感じです。

f:id:tachitutetoNosuke:20211127134504p:plain

 

順に補足

メモアプリにはオリジナルクラス「Memo」がある

「Memo」クラスには、「#タグ」プロパティの他に

「タイトル」・「メモ内容」というものがあります。

 

「Memo」には「#タグ」に相当するプロパティがある

過去記事での話では、

「#タグ」プロパティをわざわざ用意する必要があるか

ということに、簡単に触れました。

→まとめると、めんどくさいので用意しました

 

これ以降出番はありませんが、

入力画面は以下の画像です。

f:id:tachitutetoNosuke:20211127134942p:plain

画像のようにタグを登録するテキスト欄を用意しています。

 

「#タグ」プロパティには、半角スペースを境に複数のタグを格納している

りんご バナナ もも...

こんな感じで、単語(半角スペース)単語(半角スペース)...

という保存形式です。

 

プロパティをタグ1、タグ2...と

それぞれに一個ずつ保存する方法も考えましたが、

参考もとのtwitterはタグ同士を空欄で区別してましたから

これから着想し実装しました。

 

実際の登録形式とかは知らないです。

 

実際のコード

以下、方針と実際のソースコードになります。

作戦概要

  1. データからタグをList型に格納
  2. 重複があるので、重複を除く
  3. 格納したタグをfor文で、1つ1つ配置

 

登録メモデータからタグを取得する

登録してあるデータからタグをList型に格納。

基本的にはコメントしてある通りです。

「Hive〜」という記述は、

ストレージからデータを取得するための文なので

適宜、参考/無視でお願いします。

 

  1. メモループを回す
  2. ループ内で空白付きのタグ(=tag1というプロパティ)を分解
  3. さらに1つ1つのタグをListに格納
List<Category> _cates = [];// オリジナルクラス Category 重要ではない
List<Memo> _memos = [];// オリジナルクラス Memo(の中のtagがやや)大事
List<String> _tags = [];// タグ格納用 やや大事
Hive.openBox<Memo>(_memo).then((value) {// 保存データの読み込み
Box<Memo> mesBox = value;
_memos.clear();
_tags.clear();
_cates.clear();

for (Memo memo in mesBox.values) {// 保存データを(検索条件で)表示分add
if (memo.categoryCd == _categoryCd) {
if (new RegExp(r'^.*' + _contTitle.text + '.*').hasMatch(memo.title) &&
new RegExp(r'^.*' + _contMemo.text + '.*').hasMatch(memo.memo)) {
_memos.add(memo);
}
}

for (String tag in memo.tag1.split(' ')) {// ※保存データを分解し格納
_tags.add(tag);// 保存データ全てからタグをadd※※
}
_tags = _tags.toSet().toList();// ※※タグダブりがあるのでSet型にして解消
}
});

 

やや細かい補足

最後のtoSet.toList()という記述。

一度、Set型という型に変換しています。

Set型というのは、値の重複が許されないList型と思えばよくて、

この変換で、重複をのぞいてくれます。

 

なお、重複が発生する理由を具体的に述べると、

全データを1回目のループで回すので

1回目:りんご

2回目:りんご

3回目:バナナ

とかってあると、

Listの中に「りんご」タグが2個格納

→表示も2個表示

となってしまいます。

 

下手にロジック組むのも面倒だったので、

全データでループかけるのはそのままで

後からtoSetで重複を取る方針にしました。

 

取得したタグを画面に表示する

上述した通り、for文で取得したタグを配置しています。

Widget build(BuildContext context) {
if (asyncWidget != null) {
return Scaffold(
backgroundColor: Color.fromRGBO(240, 248, 255, 1.0),
persistentFooterButtons: <Widget>[// 画面下部に固定表示
Column(children: <Widget>[
SingleChildScrollView(
scrollDirection: Axis.horizontal, // 横スクロール仕込み
child: Row(children: [
for (String tag in _tags) ...{// タグ1つ1つを画面に横並べ
if(tag.trim() != '')...{
Container(
height: 90,
child: TextButton(
onPressed: () {// タグをタップで検索
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return MemoList(tag: tag);// 検索
}));
},
child: Card(
child: Container(
//height: 50,
padding: EdgeInsets.all(10),

child: Text(
'#' + tag,// 見た目のために#をつける
style: TextStyle(
fontSize: 17,
color: Colors.blueAccent,
decoration: TextDecoration.underline,
)),)// 見た目のために下線とかをつける
),
),
),
}
},
]),
),
])
],
);
}
return Scaffold(//気にしないでOK
appBar: AppBar(
title: const Text('loading...'),
));
}

この時点で、タグデータの取得ができているので

あとは簡単...つっても横並びに表示させるので

ちょっと時間取られたんですが...

 

大事なのは2点で、

  • タグ表示エリアをpersistentFootterButtonsで画面下部に固定している
  • SingleScrollViewで横スクロールを実装している
  • for文で横並びにタグを設置している

これくらいだと思います。

あとは、タップイベントに何を仕込むかとか

見た目をどうするかという問題だけです。

 

僕は、タップイベントには

検索機能(まあ、普通ですよね)を入れてます。

検索機能はまた別の話なので割愛します。

 

見た目をどうするかについては、

まあ、それっぽくしました。

twitterリスペクトってことで

「#」+登録タグ名って感じで表示してます。

 

 

以上となります。

この実装は結構楽しかった。

ソースは役立たないかもしれませんが

考え方などなんかの参考になれば幸いです。

 


基礎から学ぶ Flutter


Flutter モバイルアプリ開発バイブル

エンジニア発オンラインスクール【RUNTEQ】