デザインTIPS

BubbleでSlackのような動きをする投稿画面を実装する!最新投稿と一緒にMultiline Inputがせりあがる。

Slackのような投稿画面を作成

さるくん
さるくん
SlackのようなMultiline Input(動き)を実装したい。というお問い合わせをいただきました。

デモ

今回実装したい機能

・最新メッセーににいるときは、一緒にせり上がる⤴️
・途中のメッセージにいるときは、Inputの高さだけ増える (一緒にせり上がらない)
・メッセージは常にスクロール可
・Input は下部固定

簡単そうに見えて、実は複数の要素から出来ています。

Bubbleの新レスポンシブ機能だけでも、おしいところまでは実装できます。
しかし片方ができても、もう片方が実装できない壁にぶちあたります。

例えば
・Multiline Inputをウィンドウの下付けにして投稿のせり上がりは出来るけど、投稿内でスクロールできない
・投稿内スクロールはできるけど、今度は最新の投稿が一緒にせり上がってくれない
など

そこでプラグインのToolboxを入れ、Run javascriptを使いコードを書けば実装が可能です。

Javascriptのコードは少なめに、最低限の箇所だけにしています。

また、機能説明をわかりやすくするために、左側のサイドバーは無くし、デザインもシンプルにして解説をします。スタイルは好きな設定をご自身で行ってください。
*Bubbleの基礎を理解しているものとし、細かい部分は省きます。

後半かなり複雑になってきます。Bubbleの基礎を理解していないと難しい箇所があります。

準備:プラグインToolboxをいれる

まずは今回使用するプラグイン「Toolbox」をInstallしましょう!

このプラグインを入れると、WorkflowでJavascriptが使えるようになります。
例えば、ボタンを押したら記載したJavascriptを発動させたい時などに便利です。

表示させる仮のDataを入れる

表示に必要なDataを作っておきます。

User データ

・User type に「nickname」と「icon」のfieldを追加し、App data タブへ行き、適当なニックネームとアイコンで一人分作成します。

User データを追加する際はメールアドレスも必須なので、メールアドレスも適当なものを入れておきます。
メールアドレスは、@マークやドットなどメールアドレスの形をしている必要がありますが、Run asでテスト使用するアカウントなので実在しないメールアドレスで問題ありません。

私はこんなものを作成しました↓

Post データ

投稿した内容が入る「post」というData typeを作ります。
Fieldも「post-text」を一つ作ります。

中身のデータは後ほど実際の画面から投稿します。一旦データは空でOKです。

要素を配置する

新しくページを作成し以下の3要素を配置します。

・ヘッダー(Floating Groupで作成)
・投稿の一覧が表示されるエリア(Repeating Group)
・下部の投稿を入力するエリア(Flating Groupで作成)

図解するとこのようになります↓

上記のような見た目のデザインは一つのGroupの中に3要素を入れ、ColumnやAlign to parent を使い配置を設定することもできます。画面の仕様によってはこの方法を採用することもあります。

今回、Floatingを使った理由は「Current page scrolling position」の値をRepeating Groupから取得したいからです。この値を取得することで「今いる位置が最新投稿 か そうでないか」を判定します。

値を取得したいGroup(Repeating Group)を、ページのスクロール位置と同じにするため、ヘッダーや入力エリアを内包せず単体でページに置くようにしています。

Floating Groupはその単語の通り「浮く」のでページのスクロールに影響しません。今回のような機能を実装するにはうってつけのGroupです。

①ページ自体の設定

ページの設定は

・Container layoutをColumn
・Container alignmentをBottom-aligned

下から積み上げたいのでBottom-aligned設定(Slackのはじめたばかりのチャンネルも投稿したものを下側から積みます)

最小の高さはとりあえず少なめに500pxにしました。

②次にFloating Group ヘッダーをさくっと作ります

画面の上固定なので、Vertically float relative toはTopを。
高さは60px固定、わかりやすいように背景色を付けておきます。

③今度は下固定のFloating GroupにMultiline Inputとボタンを配置します

画面の下固定なので、Vertically float relative toはBottomを。
高さは最小値が100px(なぜならMultiline Inputの入力の行数によって高さは可変にしたいから)
Column gapを入れ、、Multiline Inputとボタンの間を20px開くように準備しておきます。
わかりやすいように背景色を付けます。

このFloating Groupの中にMultiline Inputと投稿ボタンを配置します。

Multiline Inputの高さは最小が100px、つまりFloating Groupと同じにしました。
背景色は白に。
ボタンは高さと幅固定で作成し、縦方向中央揃えに。ボタンの色は緑色にしました。
色は適当につけてください。

④投稿の一覧が表示されるエリアをRepeating Groupで作成します

Repeating Groupの中にGroupを作り、その中にアイコン、ニックネーム、投稿内容テキストの3つを配置します。
Elements tree構造はこちら↓

投稿内容がRepeating Groupで表示されればOKです。
テスト用に内容が大きめに表示されるようにしてます。

Repeating Groupの設定はこのようにしました。参考にどうぞ↓

ここでRepeating GroupのTop とBottomに何故のこの数値を入れたか?わかりますか?

②のFloating Gropのヘッダー高さと、③のFloating Groupの最小高さです。
このTopとBottomを設定することで、投稿一覧が下に隠れずに表示されるようになります。

「Group各投稿」の設定はこのようにしました。参考にどうぞ↓

Groupの中に、アイコン、ニックネーム、投稿内容が表示されるようにします。
アイコンは60x60px固定、ニックネームと投稿内容のtextはサイズ16pxにしています。

この辺りはご自身で好きな設定を。今回はテストで見やすくするためにアイコンも大きめにしています。

この状態でプレビューをし、5つほど投稿をしましょう!

プレビューをします。
表示が崩れたようになりますね。

Floating Groupをページ下部に配置しPreviewをすると表示崩れが起こります
正しく設定したものをプレビューで見る際にはURLの ?から下全て「?debug_mode=true」を削除してリロードしてください。

上記を削除すると、以下の表示になります。
Multiline Inputを含む投稿エリアがWindowの下固定になりました。
ウィンドウの高さや幅を変更し、レスポンシブになっていることも確認してください。

次にいくつか(5つほど)投稿をします。
投稿のWorkflowをまだ設定していない方は、設定をしてください。
その後、先ほど作成したユーザーで投稿したいので、Run asから画面の表示を行ない、投稿をします。

✅投稿のWorkflowを設定する
✅Run as から先ほど作成したUserで投稿を行う

5つほど投稿すると、このように下から最新の投稿が積み上がって表示されます。

Scroll to entryを使い、最新の投稿へスクロールする設定

Scroll to entry の設定をしたことがありますか?
SNSの投稿一覧など、Repeating Groupの中の「指定した特定」のところまでスクロールさせたい場合に使用します。

今回なぜ必要なのか?
今はまだ投稿数が少ないので全ての投稿内容が1画面内に表示されていいます。

しかし、試しにウィンドウの高さを最後の投稿が隠れるくらいまで狭めたり、または大量に投稿をしてみてください。
すると、こんな感じに最新の投稿したものが下に(Mutlitine Input裏に)隠れてしまいます…

これを解決するのが「Scroll to entry」です。
ちゃんと最新の投稿がひょっこり出てきてくれます(笑)
最新投稿が表示され、古い方の投稿が上部へ隠れます。

Scroll to entryを2箇所に設定をする!

Workflowで2つの設定を行います。

ページが読み込まれた時(Page is loaded)
新しい投稿があった時(Custom statesを使い、新しい投稿を検知→からのScroll させる)

ページが読み込まれた際はもちろんですが、その後に新しい投稿が追加された時もその「新しい」部分にスクロールさせる必要があります。

一つ目の、ページが読み込まれた時はシンプルで
・eventは、General の「Page is loaded」
・actionは、Element Actionsから「Scroll to entry of a repeating group」を選択します。
・Scroll to entryで、Elementは投稿が溜まっていくRepeating Groupを指定
Entry to scrollで、どこにスクロールさせるかを指定します。
最新の投稿にしたいのでリストの中の一番最新のもの「last item」を指定します

次に、新しい投稿があった場合の設定です。
このように考えます↓

・Custom statesで、現在の投稿数を保存する
・Repeating Groupの投稿数 > Custom statesで保存している投稿数 になったらScroll to entryを走らせる(投稿されるとDataの数が増えますね。そこを検知させます)

Custom statesで、現在の投稿数を保存するには、一つ目に設定した「ページが読み込まれた時」のWorkflowに Step2で Set state を追加します。

Custom statesを設定します。管理しやすいようにページ自体に設定します。

先ほどのWorkflowに Step2で Set statesをします。
追加する値、ValueはRepeating Groupの投稿数です。

次に「Repeating Groupの投稿数 > Custom statesで保存している投稿数 になったら」のeventを作成します。

・eventは、General の「Do when condition is true
・Run this を毎回 の「Every time」を選びます
*割とやりがちですがJust onceだと一度しか実行されませんのでご注意ください。
・Only whenの条件設定で「リストの数 > Custom Stateので保存した数」を指定します。

・actionは、先ほどの「Page is loaded」と全く同じ設定をします。
Step1で最新の投稿までスクロールさ、とStep2で今の投稿数をCustom stateに上書きします。

現状の挙動と問題点を確認する

さてここまで設定したら挙動を確認します。

画面の高さを低くしても、最新投稿がしっかりと表示されるようになりました!

ただしここで問題が2点あります。
①Multiline Inputの行数が高くなると、最新の投稿が隠れてしまう。下のスクロールもできない。
②最新投稿が表示されている時に、一緒にせり上がってくれない

現状の問題点を収録しました↓

問題点①を次のチャプター「Run javascriptを使い、マージンの上書きをする」で解決し

問題点②をその次のチャプター「Scroll to entryを使い…」で解決していきます。

さるくん
さるくん
長くなったけどそろそろ終盤、がんばろう!!

Run javascriptを使い、マージンの上書きをする

本当はRun javascriptを使わずにConditionalで設定できたら良いのですが、マージンを動的に変更できないので;;、仕方なくRun javascriptを使いマージンの変更を行います。

Run javascriptを使って設定すること

①Multiline Inputの行数が高くなると、最新の投稿が隠れてしまう。下のスクロールもできない。
の解決

先ほどRepeating Groupの Margin Bottomを100pxに設定しました。
この100pxに対し、Multiline Inputの高さが変更したら、マージンの変更を行います。

そうすることでMarginが取れ、投稿が隠れなくなります。

設定すること<その1>

Multiline Inputの高さを都度Custom stateに保存します。
input-heithgという名前を付け、初期値は100pxにします。(Multiline Inputの 最小高さを100pxに設定したため)

設定すること<その2>

Workflowの設定で、Do when condition is true から
・Run this は毎回の「Every time」を選択
・Only whenの条件で、Multiline Inputの高さが、Custom stateに保存した値から変化したら(同じじゃなかったら)、新たな数値に「Repeating Group一覧」のMargin Bottomの数値を変更する処理を書きました。*尚、Repeating Groupには id名を付け、それをJavascript内で指定しています。

Step1 と Step2の設定は以下の通りです↓

Run javascriptの中身を簡単に説明すると

・id名、slack-bottom と名前を付けたエレメントに対し
margin bottomを、Custom stateで保存した「input-height」の値にする

「Repeating Group一覧」と名前をつけたRepeating Group(Slackの投稿一覧が表示される)にid名「slack-bottom」を追加し、それからRun javascriptで指定しました。

プレビューして挙動を見ると、一見先ほどと何も変わっていないように見えますが、RepeatingGroupの下部にMarginがしっかり効きスクロールし投稿が全て見えるようになっています。
また、Multiline Inputの高さを減らすと、元にも戻ります。これはDo when condition is trueのOnly when(条件指定)で「is not」と指定したため、高さが高くても、低くても値が変化したら効くようになっています。

Scroll to entryを使い、最新メッセージのときだけInputを入力しながらせり上がる設定

いよいよ最後の設定です。
最後にひとつ、まだ設定できていないのが

②最新投稿が表示されている時に、一緒にせり上がってほしい

設定です。

最後の最後にちょっと頭を使う計算が必要になります✅

考え方はこうです↓

1) ページが読み込まれたら→ Custom stateに「Scrolling position」を保存
2)新しい投稿があったら→Custom stateに「Scrolling position」を保存
3)現在のScrolling positionが、とある計算した数字と同じであれば「最新投稿」と判断
4)その時だけ、Scroll to entryを発動させる

Current page scrolling positionは、以下によって数値が変化します。
・新しい投稿がある時
・過去の投稿内容をスクロールして見ている時

それゆえ、数値が変化する原因のMultiline Inputの高さを使い、今いるscrolling positionが最新投稿なのか?そうでないか?を判断します。

….めちゃくちゃ説明が難しい….です笑
ひとつずつ設定をしていきましょう!


この箇所のキーポイントは動画も用意しました!
動画は最後に貼ってあります。

数値を可視化して見えるようにしているので、あわせてみてください。


1) ページが読み込まれたら→ Custom stateに「Scrolling position」を保存

先ほど設定をしたをした「Page is loaded」のStep3に付け加えようかと思いきや、そこだとうまくいかないんですよね。Page is loadedはそのページが読み込まれてすぐ発動します、Scrolling positionは、最新の投稿つまりページで言うとスクロールし、一番最後になります。ページ全体が最後まで読み込まてからの設定をしたいので、

・Workflowページで
・eventは、Do when condition is true
・Only whenで、「Page loaded (entier)」を指定します

・actionは、Set stateで「scroll-position」という名前のCustom stateに現在のScroll positionを保存します。

Custom stateの設定はこのようにしていいます

2)新しい投稿があったら→Custom stateの「Scrolling position」を保存

新しい投稿があった際のCustom state保存は、この設定↓(投稿が増えたら)のStepに追加をします。

少し読み込む時間を置きたいので「Add pause before next action」をStep3で、
Step4で Custom stateの設定をします。

Step3でポーズを置かずにStep4のSet sateをすると値取得を失敗することがあります。
なぜならScrolling position(ページを最後まで読み込む)時間が必要だからです。

3)現在のScrolling positionが、先に保存したscrolling position+Multiline Inputで増えた高さ と同じであれば「最新投稿」と判断

3つの数値を使用して、計算をします。

<用意する数値>

A:現在のScrolling position「Current page scrolling position

B:ページ読み込んだ時 や 新規投稿があった際に保存した「Custom stateに保存した Scrolling position → 「scroll-position

C:Multiline Inputの高さ、こちらもCustom stateの保存しています →「input-height

上記を使い、計算をします

C – 100(初期マージン値) + B の値が

この結果がAと同じ値なら最新投稿を見ている(その位置が表示されている)ことになります。

やっていることは、

初期値100pxを外した純粋にMultiline Inputの増えた高さに、ページ読みこみ時/新しい投稿時のScrolling Positionを足します。

それはすなわち、最新投稿のScrolling positionにいれば、数値が同じになるはずで

それが
・同じなら→最新投稿
・違う(少ないなら)→ 前の投稿位置である
と判断できます。

・Workflowページから
・eventは、Do when condition is true
・Only whenで、and から後が説明をした計算式になります
・Step1とStep2は、Run javascriptの設定で、前のチャプターと同じ指定です
・Step3で、Scroll to entryを使い、常に最新投稿がくっつく設定(せりあがる)にしています

Only whenの部分を簡単に説明

(Multiline Inputの高さに変化があれば)

と同時に

(現在のScrolling position が(Multiline Inputの高さ – 初期マージンの100px)+ ページ読み込み/新規投稿 の際保存したScrolling position)と同じだったら

最後に、前のチャプター「Scroll to entryを使い、最新メッセージのときだけInputを入力しながらせり上がる設定」で指定したConditonalに、逆の設定「is not」版を追加します。

最新の投稿ではない場合は、投稿がくっつきせり上がるのを避けるためです。

これで完成です!
長らくお付き合いありがとうございました。

プレビューで試してみてください!うまくいきましたでしょうか?

動画で解説

さるくん
さるくん
③じゃないのに途中から③と言ってしまってますが…もうそこはご愛嬌でお願いしますm_ _m

Windowの高さが途中で変わった際の設定は、今回はしていません。
Javascriptでウィンドウの高さを取得し、scroll-positionの書き換えと計算で設定が可能です。
余力のある方や、Javascriptの設定ができる方は是非やってみてください^^

まとめ:Slackのような動きをBubbleでも実装可能!

こんな設定をBubbleでできるか?
先日お問い合わせをいただいたので、作ってみました。

Bubbleデフォルトだけの機能(コードを書かない)では現在のところ難しかったです。

ConditionalでMarginの値を動的に指定できるようになれば可能ですが、2022年9月末現在はまだ無理でした。今後可能になるような気がしておりますが(笑)

CSSもJavascriptも少しでも知識があると、Bubbleで出来ることの幅が広がります!

Bubbleの設定でお困りの方へ

思った動きを設定できない
こんな設定できるのか?

など

ご相談や代行も承っております。
お気軽にご連絡ください。

お問い合わせはこちら

ABOUT ME
おばとりっぷ
専業Bubbleエンジニア▷元webデザイナー/ディレクター▷CSSをBubbleに実装するのが得意▷日本国内のトップBubbleエンジニアとしてwebアプリ開発に携わる▷Bubble講師▷フルスクラッチ開発のアプリで起業した経験あり▷スタートアップ・起業家のBubbleアプリ開発の支援を積極的に行う。