- Home /
Ngui Text Vertical Scrollbar?
I want to create a scroll bar text field in NGUI where I can put as much text in a certain area but be able to scroll down with a vertical bar to see all of it. I haven't been able to find a NGUI tutorial that seems to do this. Also I just got Ngui pro can someone recommend some good starting tutorials? I checked out the 2 video tutorials they don't seem to cover things like I'm asking right now.
Answer by petrucio · Jan 24, 2013 at 06:27 AM
Yeah, it turned out to be a bit of a pain in the ass to do this. I'm sure there are better ways to do it, but here's my solution (it scrolls a parent object with anything in it, it can be text or other stuff). Should be pretty easy to use and self-explanatory:
using UnityEngine;
using System.Collections;
//=============================================================================
// Manages the scrolling of the contents inside a clipped panel
// Just put all objects to be scrolled inside a common parent, and then setup
// the panel, the scrollbar, and the common parent object in the inspector.
//
// Make sure this script does not sit on the scrollbar gameobject itself, since
// we will be disabling it when the scrollbar is not needed.
//=============================================================================
public class UIPanelScroller : MonoBehaviour {
public UIScrollBar scrollBar;
public UIPanel clippingPanel;
public Transform panelContentsParent;
public float checkContentsInterval = 0.1f;
public bool alwaysShowScroller = false;
private float contentsZeroY;
//========================================================================
void Start () {
this.scrollBar.onChange += this.OnScrollbarChange;
this.scrollBar.scrollValue = 0;
this.contentsZeroY = this.panelContentsParent.localPosition.y;
this.UpdateStuff();
this.StartCoroutine(this.CheckContentsChanges());
}
//========================================================================
IEnumerator CheckContentsChanges()
{
while (this.enabled) {
yield return new WaitForSeconds(this.checkContentsInterval);
this.UpdateStuff();
}
}
//========================================================================
private float _getContentsHeight() {
float relative = NGUIMath.CalculateRelativeWidgetBounds(this.panelContentsParent.transform).size.y;
return relative * this.panelContentsParent.transform.localScale.y;
}
//========================================================================
void UpdateStuff()
{
float panelH = this.clippingPanel.clipRange.w;
float contentH = this._getContentsHeight();
this.scrollBar.barSize = panelH / contentH;
this.scrollBar.gameObject.SetActive(true);
if (contentH < panelH && !this.alwaysShowScroller) {
this.scrollBar.gameObject.SetActive(false);
}
}
//========================================================================
void OnScrollbarChange(UIScrollBar ignored)
{
float nonVisibleHeight = this._getContentsHeight() - this.clippingPanel.clipRange.w + this.clippingPanel.clipSoftness.y;
float contentPos = this.contentsZeroY + (nonVisibleHeight * this.scrollBar.scrollValue);
this.panelContentsParent.transform.SetLocalPosY(contentPos);
}
}
SetLocalPosY is a simple extension method I use to avoid having to make a copy of stuff everytime I want to change a single value:
public static void SetLocalPosZ(this Transform trans, float z) {
Vector3 vector = trans.localPosition;
vector.z = z;
trans.localPosition = vector;
}
I had some issues with the clipping panel refusing to show it's contents at startup, because everything was cached up in NGUI, so I had to make this hack to shake things up:
public class UIPanelClipRefreshHack : MonoBehaviour {
public void GO() {
foreach(UIWidget widget in this.GetComponentsInChildren<UIWidget>()) {
widget.enabled = false;
widget.enabled = true;
}
}
}
Drop it on the panel, and call Go when displaying your window.
Phew!