NGUI:自己做一个popuplist
NGUI自带的PopupList对于list显示的位置不知道怎么控制,反正感觉不好用。于是就自己用UIPanel和Grid做了一个
public class PopupList : MonoBehaviour {
public Action onValueChanged;
private KeyValuePair<object, string>[] KeyValue;
public string[] content;
public int defaultIndex;
UIGrid Grid;
UILabel lbl_default;
UISprite content_bg;
UIPanel list;
private KeyValuePair<object, string> value;
public KeyValuePair<object,string> Value
{
get { return value; }
private set
{
lbl_default.text = value.Value;
this.value = value;
if (onValueChanged != null)
onValueChanged();
}
}
bool isAwake = false;
void Awake()
{
if (isAwake) return;
isAwake = true;
list = transform.Find("list").GetComponent();
Grid = transform.Find("list/grid").GetComponent();
lbl_default = transform.Find("lbl_value").GetComponent();
content_bg = transform.Find("bg").GetComponent();
InitList(KeyValue);
resetValue();
}
void Update()
{
if(!clickSwitch&&((Input.touchCount > 0 && Input.touches[0].phase == TouchPhase.Ended) || Input.GetMouseButtonUp(0)))
{
list.gameObject.SetActive(false);
}else
{
clickSwitch = false;
}
}
public void InitList(KeyValuePair<object,string>[] KVS=null)
{
if (!isAwake)
Awake();
GameObject seed = Grid.transform.GetChild(0).gameObject;
if(KVS==null)
{
KeyValue = new KeyValuePair<object, string>[content.Length];
for (int i = 0, Imax = content.Length; i < Imax; i++)
KeyValue[i] =new KeyValuePair<object, string>(content[i], content[i]);
}else
{
KeyValue = new KeyValuePair<object, string>[KVS.Length];
content = new string[KVS.Length];
for (int i=0,Imax=KVS.Length;i<Imax;i++)
{
KeyValue[i] = new KeyValuePair<object, string>(KVS[i].Key,KVS[i].Value);
content[i] = KVS[i].Value;
}
}
int count = content == null ? 0 : content.Length;
for(int i=0;i<count;i++) { Transform child; if (i>=Grid.transform.childCount)
{
child=NGUITools.AddChild(Grid.gameObject, seed).transform;
}
else
child= Grid.transform.GetChild(i);
child.Find("lbl_val").GetComponent().text = content[i];
var btn = child.Find("btn_bg").GetComponent();
btn.onClick.Clear();
EventDelegate.Add(btn.onClick, onClickBtn_Item);
}
for(int i=Grid.transform.childCount-1;i>=count;i--)
{
if (i > 0)
{
//此处应该用DestroyImmediate 否则会导致后面计算的时候Grid下的child没有减少
DestroyImmediate(Grid.transform.GetChild(i).gameObject);
}
}
Grid.Reposition();
list.gameObject.SetActive(false);
AdjustListSize();
}
void AdjustListSize()
{
Bounds bound = NGUIMath.CalculateRelativeWidgetBounds(list.transform, Grid.transform, true);
Bounds btn_bound = NGUIMath.CalculateRelativeWidgetBounds(list.transform, content_bg.transform, true);
Vector4 clip = list.baseClipRegion;
clip.w = bound.size.y+10;
clip.y = bound.center.y;
list.baseClipRegion = clip;
}
public void resetValue(bool autoCallBack=false)
{
setValueByIndex(defaultIndex, autoCallBack);
}
public void setValueByIndex(int index,bool autoCallBack=true)
{
if (KeyValue != null && index >= 0 && index < content.Length) { if (autoCallBack) Value = KeyValue[index]; else { value = KeyValue[index]; lbl_default.text = value.Value; } } } public void setValueByKey(object key, bool autoCallBack = true) { int index = Array.FindIndex(KeyValue, c=>c.Key.Equals(key));
if (index < 0) return;
var val = KeyValue[index];
if (autoCallBack)
{
Value = val;
}
else
{
value = val;
lbl_default.text = val.Value;
}
}
bool clickSwitch = false;
public void onClickBtn_Switch()
{
clickSwitch = true;
list.gameObject.SetActive(!list.gameObject.activeSelf);
}
public void onClickBtn_Item()
{
UIButton curBtn = UIButton.current;
int index = curBtn.transform.parent.GetSiblingIndex();
Value = KeyValue[index];
}
}
Item的形式
popList的item用的是keyValue的形式,显示在UI上的只是Value,选择了一个Item之后的到的Value也是一个键值对,对所选的Item的处理应该依赖于key,而不是value。如果在初始化这个popList的时候没有设置key,则将会直接用value来充当key。对key的设置应该是用代码传递的。而如果仅需要设置value的话则可以只在面板上直接设置,只是这样的话key就会直接用value来替代。
list下拉菜单的显示位置
做这个popuplist的原因就是ngui自身的list显示位置不好控制,我这的list的位置则由grid来控制,list Panel的位置会自动适应其下的grid,grid摆在哪里,下拉菜单的起始位置就在哪里
另外上面的代码中有3个接口可供调用,用来重置默认值或设置一个值
public void resetValue(bool autoCallBack=false)//可以在面板上指定默认值的下标
public void setValueByIndex(int index,bool autoCallBack= true)
public void setValueByKey(object key, bool autoCallBack = true )
3个接口都有一个autoCallBack脚本,默认为true,用来标记是否需要调起onValueChange的回调。 因为有时候reset一下并不需要唤起回调
贴一个效果图 和我的层级结构