Thunkableで検索機能を実装する
このエントリーでは、Thunkableで検索機能を実装する方法を紹介します。
Thunkableでアプリ開発をしていると、検索機能を実装したいことがよくあります。検索はやりたいことによっていくつかのパターンに実装方法が分かれるため、このエントリーでは最も使われる頻度が高いと思われる主要パターンの実装方法を解説していきます。
具体例があった方がわかりやすいので、このエントリーでは、ThunkableのLocal Table Data Sourceで以下のテーブル(ThunkableSearchTableのTable1)が存在することとします。
Name | Department | YearJoined | Icon | |
---|---|---|---|---|
John Smith | smith@example.com | Sales | 2015 | panda.jpg |
Emily Johnson | emily.johnson@example.com | Marketing | 2018 | fox.jpg |
Michael Williams | williams@example.com | Engineering | 2020 | dolphin.jpg |
Emma Smith | emma.smith@example.com | Human Resources | 2017 | cat.jpg |
William Davis | davis@example.com | Finance | 2019 | narcissus.jpg |
Olivia Johnson | johnson@example.com | Marketing | 2016 | european.jpg |
James Wilson | wilson@example.com | Engineering | 2021 | dogs.jpg |
Sophia Davis | davis@example.com | Finance | 2014 | landscape.jpg |
Benjamin Taylor | taylor@example.com | Engineering | 2022 | birds.jpg |
Ava Wilson | wilson@example.com | Sales | 2013 | forest.jpg |
検索ヒットする値を見つけたいのか、値が存在する行番号を見つけたいのか
検索をする場合、実際にやりたいのは、「検索ヒットする値を見つけたい」場合と「検索ヒットする値が存在する行(レコード)番号を見つけたい」場合の2パターンが大半だと思います。
「検索ヒットする値を見つけたい」というのは、検索対象の列と検索結果の値が保存されている列が同一というパターンです。例えば、「Smith」が含まれる名前をすべて取得したい場合、上記のLocal Tableの検索対象の列はName列です。そして、検索結果として得たい「John Smith」と「Emma Smith」という値も同じくName列に存在します。この場合は、Name列の情報をList variableに格納し、検索処理でフィルターした結果をList variableに抜き出すだけです。
以下はスクリーンオープン時に、Name列の中から「Smith」が含まれる値をすべて取得して、SearchResultListという名前のSimple Listに表示させる方法です。
検索ヒットする値を見つける(App UI)
検索ヒットする値を見つける(Block)
一方、「検索ヒットする値が存在する行(レコード)番号を見つけたい」というのは、検索対象の列と検索結果の値が保存されている列が異なるというパターンです。例えば、「Smith」が含まれる名前の人のすべての所属部署名を取得したい場合、上記のLocal Tableの検索対象の列はName列です。しかし、所属部署の情報はName列には存在しないので、Department列を見ないといけません。Thunkableの場合は複数列をまとめて処理するのが難しいので、検索ヒットする値がName列に存在する行(レコード)の行番号を一度取得し、Department列の該当行番号の値を取得する、というステップを踏む必要があります。
以下はスクリーンオープン時に、Name列の中から「Smith」が含まれる値が存在する行番号を取得し、Department列の該当行番号の値をすべて取得し、SearchResultListという名前のSimple Listに表示させる方法です。
検索ヒットする値が存在する行番号を見つける(App UI)
検索ヒットする値が存在する行番号を見つける(Block)
検索キーワードをユーザーが入力できるようにする
上記の例では検索文字列は「Smith」と決め打ちにしていますが、ユーザーが検索キーワードを自由に入力して検索できるようにしたい場合は、Text Inputの値(Text)を使って、検索ボタン実行時に検索が行われるようにします。
以下は、SearchButtonという名前のボタンのクリック時に、SerchTextInputという名前のText InputのTextを使って検索するように変更したものです。検索は繰り返し行われる可能性が出てきましたので、検索処理に使っている変数は都度リセットするようにしました。
検索キーワードを入力する(検索前)(App UI)
検索キーワードを入力する(検索後)(App UI)
検索キーワードを入力する(Block)
部分一致検索させたいのか、完全一致検索させたいのか
ここまでの検索ヒットは「〜が含まれる」という表現を使ってきたように、部分一致検索を使用してきました。部分一致検索というのは、検索対象の値に対して、検索キーワードが一部分だけでも含まれていれば検索ヒットであるとみなす方法です。それに対して、検索対象の値と検索キーワードが完全に一致していないと検索ヒットとみなさないのは完全一致検索といいます。
たいていの検索は部分一致検索で問題ないと思います。例えば、ユーザーがアプリに投稿した複数のコメントの中から特定キーワードを含むコメントを探し出す場合は、部分一致検索が最適です。一方で、その条件に完全一致しないものはノイズになる場合があります。例えば、会員番号「R5」のユーザーの投稿だけ探すのに、「R51」や「XR5」のユーザーの投稿も表示されてしまうのは余計かもしれません。このような場合は完全一致検索を使った方が安全です。
部分一致検索は上記のBlock例で示したようにdoes "abc" contains "b"
を使用します。「abc」部分にあたるテキストに「b」というテキストが含まれる場合はTrue、含まれない場合はFalseが返ってきますので、if文でその結果を受け取って、Trueの時はdo、Falseの時はelseで処理することで、部分一致するかしないかを判定させることができます。
一方、完全一致は検索対象の値と検索キーワードがまったく同一であることかを判定するだけですので、イコールで比較するだけです。
以下は、Eメールアドレスを検索すると名前を表示するアプリです。上記のLocal Tableを見て分かるように、先に入社したOlivia JohnsonさんのEメールは「johnson@example.com」です。そして、その後に入社したEmily JohnsonさんのEメールは「emily.johnson@example.com」です。OliviaさんのEメールアドレスで検索した場合、部分一致検索ではOliviaさんの名前だけでなく、Emilyさんの名前も表示されてしまうのですが、完全一致検索ではOliviaさんの名前しか表示されなくなります。
部分一致検索させる(App UI)
完全一致検索させる(App UI)
完全一致検索させる(Block)
Data Viewer Listで検索結果のみを表示させる
検索結果の表示方法について、検索ヒットする値で見つける方法であれば、List形式で取得した検索結果の値のリストをSimple Listに適用するだけで十分だと思います。
しかし、ソーシャルネットワーク系のアプリを開発していて、画像表示にData Viewer List(あるいはData Viewer Grid。以下同様)を使っている方から、Data Viewer Listに検索結果のみ表示したい、という要望を聞く機会が結構な頻度であります。
Data Viewer ListはTableのデータを、ある程度決まったレイアウトパターンで「そのまま表示」させることに特化したコンポーネントなので、普通のやり方では検索結果のみを表示対象には出来ません。私もそのような質問には「出来ないと考えてください」とお伝えして、代替案を案内しています。ただし、力技を使えば技術的には不可能ではないので、ここでやり方を紹介します。エレガントではないので、個人的にはあまり好みではありません。
Data Viewer ListはTableのデータをそのまま表示するものですので、検索の度に一時的なテーブルを生成する方法で実装を行います。Local Tableとして、まったく同じ列構成のTableを新規作成します。Tableの名前はここではTempSearchTableとします。列名は厳密には同じでなくても良いのですが、今回は元のTableと同じ名前にします。中身は空で構いません。Data Viewer Listが参照するData Sourceは新規Tableの方にします。
一時テーブルを作成する
Blockの設定です。まず、スクリーンオープン時に一時テーブルのデータを全部消去し、元Tableのデータを一時テーブルにそのまま上書きして、DataViewerListをRefresh Dataします。写真データも含めて10件が表示されることを確認しました。ちなみに写真はPixabayを使用しています。
スクリーンオープン時の表示(全件表示)(AppUI)
スクリーンオープン時の表示(全件表示)(Block)
次は検索結果のみフィルターする機能のBlock設定です。検索値が存在する行番号が分かればいいだけなので、これまでやってきた内容を応用して以下のようにBlockを組みます。変数名や参照するTable名が多少ややこしいので注意が必要です。結果、以下のようにData Viewer Listで検索結果のみを表示させることができました(名前にSmithが含まれるもの2件のみ表示)。
検索時の表示(検索ヒットしたもののみ表示)(AppUI)
検索時の表示(検索ヒットしたもののみ表示)(Block)
好みのコンポーネントで検索結果を表示させる
上記のようにData Viewer Listで検索結果を表示させることは出来るのですが、Data Viewer Listは表示パターンが限られているので、アプリの見た目にこだわりたい人にとっては物足りない感もあると思います。その場合は、ImageコンポーネントやLabelコンポーネントを組み合わせて検索結果を表示させることもできます。
スクリーンオープン時の表示(全件表示)(AppUI)
検索時の表示(検索ヒットしたもののみ表示)(AppUI)
こちらは自分の好きな場所にコンポーネントを配置できますので、レイアウトや文字の装飾にこだわったり、SNSアプリでよくあるLikeボタンやコメントボタンを自由に配置できます。
コンポーネント配置(Design)
一方で、ブロックプログラミングの方はかなり煩雑になりがちです。画面制御は繰り返し実行される共通機能となるため、Function(関数)にまとめて配置するのがおすすめです。それでも、コンポーネントの数に応じてブロックのサイズがどんどん肥大化します。また、コンポーネントの表示・非表示制御が地味に手間がかかります。ここでは使っていませんが、Groupコンポーネントにまとめてしまって、Groupごと表示・非表示制御をさせるなど工夫はしたほうがいいと思います。こういうのをやってみると、Data Viewer Listは手間が少なくて簡単だと感じます。
マニュアルオープン時の処理と検索ボタンクリック時の処理(Block)
検索結果表示Function〜その2に続く〜(Block)
検索結果表示Function〜その1の続き〜(Block)
以上で、Thunkableで検索機能を実装する方法の紹介を終了します。検索機能は非常に多くの開発者が提供したいと思う機能なのですが、Thunkableの基本機能ではその機能を提供していないので、自分で実装する必要があります。Thunkableで開発を行っている多くの方にとっては少し難しすぎるかなと思うのですが、このエントリーを読んで自分でも実装してみたいと思われた方は是非チャレンジしてみてください。
アプリURL
Discussion