using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Linq; using System; public class ComboBox : MonoBehaviour { private Dictionary<object, object> dataSource; private object currentValue; private object currentDisplayText; private int currentIndex; private GUISkin skin; private Rect rect; private Rect relativeRect; private Rect parentWinRect; private Rect rectList; private Rect rectListView; private Rect rectListViewGroupTop; private Rect rectListViewGroupBottom; private bool showList; private int listItemCount; private Vector2 scrollPosition; private Texture2D scrollBarBg; private Texture2D scrollBarThumb; private float showListTime; private int guiDepth; private bool alreadyInitGuiDepth; ////// 选择项更改事件参数 /// public class SelectItemChangedArgs : EventArgs { private object itemValue; private object itemDisplayText; public object ItemValue{ get{ return itemValue; } } public object ItemDisplayText{ get{ return itemDisplayText; } } public SelectItemChangedArgs (object iValue, object iDisplayText) { itemValue = iValue; itemDisplayText = iDisplayText; } } /// /// 选择项更改事件 /// public event EventHandler OnSelectItemChanged; public object SelectValue { get { return currentValue; } } public object SelectDisplayText { get { return currentDisplayText; } } public float ShowListTime { get { return showListTime; } } /// /// 数据源 /// public Dictionary<object, object> DataSource{ set{ dataSource = value; currentDisplayText = null; currentValue = null; } get{ return dataSource; } } /// /// 初始化各项参数,控件应该只调用一次此方法,进行重置数据源直接使用DataSource属性即可 /// /// /// A /// /// /// A "/> /// /// /// A/// /// /// A /// /// /// A /// /// /// A /// /// /// A /// public void Init(GUISkin s, Dictionary<object, object> data, Rect r, int listCount, Texture2D barBg, Texture2D barThumb, int depth) { skin = s; dataSource = data; relativeRect = r; listItemCount = listCount; scrollBarBg = barBg; scrollBarThumb = barThumb; currentIndex = -1; //将控件置于当前GUI元素之上,并且只在第一次调用初始化方法设置GUI深度,防止循环中重复调用 if (!alreadyInitGuiDepth){ guiDepth = GUI.depth - 1; alreadyInitGuiDepth = true; } currentDisplayText = null; currentValue = null; GUI.skin.verticalScrollbar.normal.background = scrollBarBg; GUI.skin.verticalScrollbar.margin = new RectOffset (0, 0, 0, 0); GUI.skin.verticalScrollbarThumb.normal.background = scrollBarThumb; } /// /// 设置父类容器的坐标范围,计算控件在屏幕上真正的坐标位置 /// /// /// A /// public void SetParentRect(Rect rectParent) { parentWinRect = rectParent; rect = new Rect(parentWinRect.x + relativeRect.x, parentWinRect.y + relativeRect.y,relativeRect.width,relativeRect.height); } /// /// 强行设置下拉列表是否是示 /// /// /// A /// public void SetShowList(bool show) { if (showList){ showList = show; } } /// /// 绘制下拉列表框 /// public void Draw () { if (skin == null || dataSource == null) { return; } if (currentDisplayText == null || currentValue == null) { if (dataSource.Count > 0) { currentDisplayText = dataSource.Values.First (); currentValue = dataSource.Keys.First (); currentIndex = 0; } else{ currentDisplayText = "无"; currentValue = -1; currentIndex = -1; } } if (GUI.Button (rect, currentDisplayText == null ? "" : currentDisplayText.ToString (), skin.GetStyle ("combobox"))) { showList = !showList; if (showList) { showListTime = Time.time; } else { showListTime = 0f; } } this.DrawList(); } /// /// 绘制列表项 /// public void DrawList () { if (showList == true) { this.calculateItemCount(); if (listItemCount < dataSource.Count) { //为了留出最方下的横线,这里高度减1 rectList = new Rect (rect.x, rect.y + rect.height, rect.width, rect.height * listItemCount - 1); rectListView = new Rect (rect.x, rect.y + rect.height, rect.width - GUI.skin.verticalScrollbar.fixedWidth, rect.height * dataSource.Count); rectListViewGroupTop = new Rect (rectList.x, rectList.y, rectList.width, rectList.height + 1 - rect.height); rectListViewGroupBottom = new Rect (rectList.x, rectList.y + rectListViewGroupTop.height, rectList.width, rect.height); GUI.Box(rectListViewGroupTop,"", skin.GetStyle ("comboxlist")); GUI.Box(rectListViewGroupBottom,"", skin.GetStyle ("comboxlistbottom")); //scrollPosition = GUI.BeginScrollView (rectList, scrollPosition, rectListView, false, true); scrollPosition = Vector2.Lerp(scrollPosition,GUI.BeginScrollView(rectList, scrollPosition, rectListView, false, true),0.5f); float top = rectList.y; for (int i = 0; i < dataSource.Count; i++) { drawItem(new Rect (rectList.x, top, rect.width, rect.height),i); top += rect.height; } GUI.EndScrollView (); } else if (dataSource.Count>0){ rectList = new Rect (rect.x, rect.y + rect.height, rect.width, rect.height * dataSource.Count - 1); rectListViewGroupTop = new Rect (rectList.x, rectList.y, rectList.width, rectList.height + 1 - rect.height); rectListViewGroupBottom = new Rect (rectList.x, rectList.y + rectListViewGroupTop.height, rectList.width, rect.height); GUI.Box(rectListViewGroupTop,"", skin.GetStyle ("comboxlist")); GUI.Box(rectListViewGroupBottom,"", skin.GetStyle ("comboxlistbottom")); GUI.BeginGroup(rectList); float top = 0; for (int i = 0; i < dataSource.Count; i++) { drawItem(new Rect (0, top, rect.width, rect.height),i); top += rect.height; } GUI.EndGroup(); } } } /// /// 当listItemCount为0时,动态计算可以容纳的数据行数 /// private void calculateItemCount() { if (listItemCount==0){ int availableAreaHeight = (int)(parentWinRect.height - relativeRect.y - relativeRect.height -1); listItemCount = availableAreaHeight/(int)relativeRect.height; } } /// /// 绘制内容项,并响应事件 /// /// /// A /// /// /// A /// private void drawItem (Rect r,int index) { if (GUI.Button (r, dataSource.Values.ElementAt(index).ToString (), skin.GetStyle ("comboxitem"))) { currentDisplayText = dataSource.Values.ElementAt (index); currentValue = dataSource.Keys.ElementAt (index); if (currentIndex!=index){ currentIndex = index; if (OnSelectItemChanged!=null){ OnSelectItemChanged(this,new SelectItemChangedArgs(currentValue,currentDisplayText)); } } showList = false; } } void OnGUI() { GUI.depth = guiDepth; this.Draw(); } /// /// 按时间比较各ComboBox控件的顺序,初衷是为了点击新的控件时,其它ComboBox控件下拉列表自动隐藏 /// public class ShowListComparer : IComparer { #region IComparer[ComboBox] implementation int IComparer .Compare (ComboBox x, ComboBox y) { return x.showListTime.CompareTo (y.showListTime) * -1; } #endregion } }