【Unity】【uGUI】 滑らかにスクロールするチャットウィンドウのようなものを作りたかった話
お疲れ様です。ぐーるです。
いきなりですけど、表題のようなものが作りたくて四苦八苦してました。
結局自作に終わったんですが、ちょっと経緯をメモっておこうかと。
ScrollRectで余裕っしょ
UnityにはScrollRectがあって、それはnormalizedPositionっていう値を持っていて、
その値でスクロール位置を制御できます。
こちらを利用しようとまず考えました。
追加する行について
今回作ろうとしていたのはチャットウィンドウなんで、文字の長さや改行によって
追加される行の高さはまちまちな訳です。
これはLayoutElementと自分計算で行けるなということで
_messageText.text = strMessages[Random.Range(0, strMessages.Length)]; // 適当なメッセージ _messageText.rectTransform.sizeDelta = new Vector2(_messageText.rectTransform.sizeDelta.x, _messageText.preferredHeight); _backGroundImage.GetComponent<RectTransform>().sizeDelta = new Vector2(_backGroundImage.GetComponent<RectTransform>().sizeDelta.x, _messageText.preferredHeight + 40);
こんな感じで、テキストの高さから計算して設定すればとりあえずいいでしょう。
スクロールイメージ
最初に起こしたイメージは
というイメージでAddする度に0.0fへ
毎回スクロールさせてあげればいいじゃん。シンプル。
実際これは問題無く実装出来ました。
void Update () { if (isScroll) { var val = _scrollRect.verticalNormalizedPosition; if(val > 0){ val -= scrollSpeed * Time.deltaTime; _scrollRect.verticalNormalizedPosition = val; } else { _scrollRect.verticalNormalizedPosition = 0; isScroll = false; } } } void AddRow() { var go = Instantiate(_rowPrefab); go.transform.SetParent(_tableContent.transform); isScroll = true; }
工夫すると
チャットシステムとはいえ、単純に作るとInstantiateの嵐になってしまいます。
なので、出来るだけコンポーネントを使い回したいなと考えました。
このようになると単純なスクロールでは上手くいかず、
少し計算が必要になりました。
float contentHeight = _tableContent.GetComponent<RectTransform>().sizeDelta.y; // 全体の長さ float beforeTextHeight = row.GetComponent<RectTransform>().sizeDelta.y; // 前の行の高さ float afterTextHeight = row.Create(); // Createの中では、ランダムにメッセージを生成している。行の高さを返却 float hDelta = contentHeight - beforeTextHeight + afterTextHeight; // 前回のを消し、新しい高さを計算 float normal = afterTextHeight / hDelta; // 最終的なスクロール位置 Debug.Log("contentHeight == " + contentHeight + " | before " + beforeTextHeight + " | after " + afterTextHeight + " | normal " + normal + " | delta " + (hDelta)); row.transform.SetAsLastSibling(); // 最下部にスライド
こんな感じで計算すると追加した行の手前に丁度フォーカスが動きます。
後はそのまま0.0fへ向かってスクロールすればOKです。
スクロールはいい感じです。
が、全体としてはどうでしょうか。
ScrollRectの再計算なのかガタっと表示が動く事があるため、微妙に荒い感じに…。
(gifで見ると悪くなく見えますが、実際見るとちょっとガタつきがあることがあります)
結局自作?
使い回しをせず、素直にInstantiateすれば問題ないです。
自動スクロールさせない、なんていうのも良いし、
アニメーションさせず、0.0fへ飛ぶような感じでも誤魔化せそう。
ちょっとヘンな事をしようとすると上手く行かなかった…って話でした。
実装でカバー出来そうだけど、自作のほうが制御が楽?