unity3d中自带的GUI实现下拉列表框

时间:2021-12-06 10:11:00
using UnityEngine;

using System.Collections;

using System.Collections.Generic;

using System.Linq;

using System;



public  class ComboBox : MonoBehaviour

{

     private Dictionary< objectobject> 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;

    

     ///   <summary>

    
///  选择项更改事件参数 

    
///   </summary>

     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;

        }

    }

    

     ///   <summary>

    
///  选择项更改事件 

    
///   </summary>

     public  event EventHandler<SelectItemChangedArgs> OnSelectItemChanged;



     public  object SelectValue {

         get {  return currentValue; }

    }



     public  object SelectDisplayText {

         get {  return currentDisplayText; }

    }



     public  float ShowListTime {

         get {  return showListTime; }

    }

    

     ///   <summary>

    
///  数据源 

    
///   </summary>

     public Dictionary< objectobject> DataSource{

         set{

            dataSource = value;

            currentDisplayText =  null;

            currentValue =  null;

        }

         get{

             return dataSource;

        }

    }

    

     ///   <summary>

    
///  初始化各项参数,控件应该只调用一次此方法,进行重置数据源直接使用DataSource属性即可 

    
///   </summary>

    
///   <param name="s">

    
///  A  <see cref="GUISkin"/>

    
///   </param>

    
///   <param name="data">

    
///  A  <see cref="Dictionary<System.Object, System.Object> "/>

    
///   </param>

    
///   <param name="r">

    
///  A  <see cref="Rect"/>

    
///   </param>

    
///   <param name="listCount">

    
///  A  <see cref="System.Int32"/>

    
///   </param>

    
///   <param name="barBg">

    
///  A  <see cref="Texture2D"/>

    
///   </param>

    
///   <param name="barThumb">

    
///  A  <see cref="Texture2D"/>

    
///   </param>

    
///   <param name="depth">

    
///  A  <see cref="System.Int32"/>

    
///   </param>

     public  void Init(GUISkin s, Dictionary< objectobject> 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 ( 0000);

        GUI.skin.verticalScrollbarThumb.normal.background = scrollBarThumb;

    }

    

     ///   <summary>

    
///  设置父类容器的坐标范围,计算控件在屏幕上真正的坐标位置 

    
///   </summary>

    
///   <param name="rectParent">

    
///  A  <see cref="Rect"/>

    
///   </param>

     public  void SetParentRect(Rect rectParent)

    {

        parentWinRect = rectParent;

        rect =  new Rect(parentWinRect.x + relativeRect.x, parentWinRect.y + relativeRect.y,relativeRect.width,relativeRect.height);

    }

    

     ///   <summary>

    
///  强行设置下拉列表是否是示 

    
///   </summary>

    
///   <param name="show">

    
///  A  <see cref="System.Boolean"/>

    
///   </param>

     public  void SetShowList( bool show)

    {

         if (showList){

            showList = show;

        }

    }

    

     ///   <summary>

    
///  绘制下拉列表框 

    
///   </summary>

     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();

    }

    

     ///   <summary>

    
///  绘制列表项

    
///   </summary>

     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,  falsetrue), 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();

            }

        }

    }

    

     ///   <summary>

    
///  当listItemCount为0时,动态计算可以容纳的数据行数 

    
///   </summary>

     private  void calculateItemCount()

    {

         if (listItemCount== 0){

             int availableAreaHeight = ( int)(parentWinRect.height - relativeRect.y - relativeRect.height - 1);

            listItemCount = availableAreaHeight/( int)relativeRect.height;

        }

    }

    

     ///   <summary>

    
///  绘制内容项,并响应事件 

    
///   </summary>

    
///   <param name="r">

    
///  A  <see cref="Rect"/>

    
///   </param>

    
///   <param name="index">

    
///  A  <see cref="System.Int32"/>

    
///   </param>

     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();

    }

    

     ///   <summary>

    
///  按时间比较各ComboBox控件的顺序,初衷是为了点击新的控件时,其它ComboBox控件下拉列表自动隐藏 

    
///   </summary>

     public  class ShowListComparer : IComparer<ComboBox>

    {

         #region IComparer[ComboBox] implementation

         int IComparer<ComboBox>.Compare (ComboBox x, ComboBox y)

        {

             return x.showListTime.CompareTo (y.showListTime) * - 1;

        }

         #endregion

    }

}