木骰

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一下并不需要唤起回调

贴一个效果图 和我的层级结构

— 于 共写了3797个字
— 文内使用到的标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*