Implementing a chat UI with NGUI scrollView

So, what I was trying to do earlier today was to implement a chat window with Unity and NGUI that follows the standard UX of a chat app, which means it shows messages in a top-down order within the message field and once the messages go off the viewport, it automatically scrolls to the end of the list.

At first I thought this should be as simple as few clicks in the editor, however, it turned out to be tricky and require customizing the NGUI scrollView script.

The problem with scrollView’s default behavior is that you can only reset it’s position to the pivot, which means there is no off-the-shelf API that you can call to reset your scrollView’s content to scrollView’s bottom while having a pivot of top or any other values than bottom. This sucks because having a pivot of bottom will give you a bottom-up experience of the chat, which is odd when the message doesn’t overflow.

Realized this, I was trying to google some solutions cause I was too lazy to write my own. Unfortunately, I found a couple of similar questions with only the answer of using CenterOnChild. Come on! Have you guys ever seen a transition that scrolls the messages down to the latest one when opening a conversation? That might be cool but definitely unnecessary. So I decided to write my own solution.

Since what I really want is just scrolling the viewport down to the bottom only when the content overflows, I made a quick and dirty hack to UIScrollView.cs, you should clean up the codes and wrap it in a proper way if you’d like to use it in production. But this simple solution worked just as it should be.

public void ResetPositionToBottom(){
  if (NGUITools.GetActive(this))
  {

            Bounds b = bounds;
            Vector2 bmin = b.min;
            Vector2 bmax = b.max;

            Vector4 clip = mPanel.finalClipRegion;
            int intViewSize = Mathf.RoundToInt(clip.z);
            if ((intViewSize & 1) != 0intViewSize -= 1;
            float halfViewSize = intViewSize * 0.5f;
            halfViewSize = Mathf.Round(halfViewSize);
            
            if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
                halfViewSize -= mPanel.clipSoftness.x;
            
            float contentSize = bmax.y – bmin.y;
            float viewSize = halfViewSize * 2f;

            // Invalidate the bounds
            mCalculatedBounds = false;
            Vector2 pv = Vector2.one;

            // only trigger the autoscrolltobottom if contents size if bigger than the view size
            if(contentSize>viewSize)
                pv = NGUIMath.GetPivotOffset(UIWidget.Pivot.Bottom);
            else 
                pv = NGUIMath.GetPivotOffset(contentPivot);
            
            // First move the position back to where it would be if the scroll bars got reset to zero
            SetDragAmount(pv.x1f – pv.yfalse);
            
            // Next move the clipping area back and update the scroll bars
            SetDragAmount(pv.x1f – pv.ytrue);
      }
}

Screen Shot 2015-11-06 at 1.03.38 AMHere is a demo of the chat window after hacking on NGUI.

Just add the above function to NGUI’s UIScrollView.cs file and call it outside when your contents are ready.

Hope this post will save you some time and if you have a better solution please leave a comment!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s