Unity 多級下拉菜單


 Unity自帶的Dropdown只能出現一級下拉菜單 在嘗試修改之后 無法實現 索性自己寫了一個

效果如下

組件結構

 

主按鈕 MainButton 點擊之后出現菜單

菜單 dropdownpanel 放置多個按鈕Item

菜單列表 dropdown列表 放置多個菜單

按鈕Item dropdownItem模板 每個菜單按鈕的模板

獲取dropdownItem模板大小 本想自動適配大小 后來沒有用

背景按鈕隱藏 一個巨大的下層Mask 用於點擊外部關閉整個菜單

代碼

界面部分

  1 public class MoreDropdown : MonoBehaviour
  2     {
  3         [Header("主按鈕")]
  4         public Button mainButton;
  5         [Header("dropdownPanel模板")]
  6         public Image dropdownPanel;
  7         [Header("dropdown列表")]
  8         public Image dropdownGrid;
  9         [Header("dropdownItem模板")]
 10         public Button dropdownItem;
 11         [Header("獲取dropdownItem模板大小")]
 12         public RectTransform dropdownItemRT;
 13         [Header("背景按鈕隱藏")]
 14         public Button hideBG;
 15         //下拉菜單集
 16         private List<Image> dropdownPanels = new List<Image>();
 17         //菜單數據
 18         private static List<IMoreDropdownInfo> allInfo;
 19         //記錄點擊位置順序
 20         private int[] clickOrder = new int[10];
 21         private int orderIndex = 0;
 22         //是否顯示
 23         private bool isShowFirstPanel = true;
 24         //選中按鈕
 25         private List<Button> pointerButtonList = new List<Button>();
 26         //當前選中按鈕數據
 27         private Button enterButton;
 28         private int enterButtonLevel;
 29         private IMoreDropdownInfo enterButtonInfo;
 30         //按鈕選中顏色狀態
 31         private enum ButtonColorState
 32         {
 33             Normal,
 34             Enter,
 35             Exit,
 36             Click,
 37         }
 38         //多下拉菜單輔助Action
 39         public Action onCreateDropdown;
 40 
 41         void Awake()
 42         {
 43             //下拉菜單
 44             mainButton.onClick.AddListener(delegate ()
 45             {
 46                 if (isShowFirstPanel)
 47                 {
 48                     isShowFirstPanel = false;
 49                     hideBG.gameObject.SetActive(true);
 50                     //置於頂部
 51                     transform.SetAsLastSibling();
 52                     //開始創建列表
 53                     onCreateDropdown?.Invoke();
 54                     CreateDropdown(0, allInfo);
 55                 }
 56                 else
 57                 {
 58                     HideFirstPanel();
 59                 }
 60             });
 61 
 62             //背景全部隱藏
 63             hideBG.onClick.AddListener(delegate ()
 64             {
 65                 HideFirstPanel();
 66             });
 67         }
 68 
 69         /// <summary>
 70         /// 創建下拉菜單
 71         /// </summary>
 72         /// <param name="level">第幾級菜單</param>
 73         private void CreateDropdown(int level, List<IMoreDropdownInfo> infoList)
 74         {
 75             Image dropdown = Instantiate(dropdownPanel);
 76             dropdownPanels.Add(dropdown);
 77             dropdown.transform.parent = dropdownGrid.transform;
 78             dropdown.transform.localScale = new Vector3(1f, 1f, 1f);
 79             dropdown.gameObject.SetActive(true);
 80 
 81             dropdownGrid.gameObject.SetActive(true);
 82 
 83             for (int k = 0; k < infoList.Count; k++)
 84             {
 85                 //二級及以上的第一位不顯示(填充到了前一級的位置)
 86                 if ((level > 0) && (k == 0))
 87                     continue;
 88 
 89                 IMoreDropdownInfo info = infoList[k];
 90                 Button cloneButton = Instantiate(dropdownItem);
 91                 cloneButton.transform.parent = dropdown.transform;
 92                 cloneButton.transform.localScale = new Vector3(1f, 1f, 1f);
 93                 Image dropdownButton = cloneButton.GetComponent<Image>();
 94                 Text dropdownText = cloneButton.transform.Find("dropdownText").GetComponent<Text>();
 95                 Image dropdownArrow = cloneButton.transform.Find("dropdownArrow").GetComponent<Image>();
 96 
 97                 //創建時 選中按鈕默認記錄第一個
 98                 if (k == 1)
 99                     pointerButtonList.Add(cloneButton);
100                 //判斷是否有下一級
101                 if (info.str != null)
102                 {
103                     dropdownArrow.gameObject.SetActive(false);
104                     dropdownText.text = info.str;
105                 }
106                 else
107                 {
108                     dropdownArrow.gameObject.SetActive(true);
109                     dropdownText.text = info.list[0].str;
110                 }
111 
112                 //處理選中狀態
113                 cloneButton.gameObject.SetActive(true);
114                 MCsUIListener listener = MCsUIListener.Get(cloneButton.gameObject);
115                 listener.onEnter = (go, eventData) =>
116                 {
117                     SetButtonState(cloneButton, ButtonColorState.Enter);
118                     enterButton = cloneButton;
119                     enterButtonLevel = level;
120                     enterButtonInfo = info;
121                 };
122           //這是項目封裝的代碼 可以繼承IPointerClickHandler接口 123 listener.onExit = (go, eventData) => 124 { 125 SetButtonState(cloneButton, ButtonColorState.Exit); 126 enterButton = null; 127 enterButtonLevel = -1; 128 enterButtonInfo = null; 129 }; 130 131 listener.onUp = (go, eventData) => 132 { 133 if (enterButton != null) 134 OnSelectDropdownItem(); 135 }; 136 } 137 } 138 139 /// <summary> 140 /// 移除第幾級及后的菜單 141 /// </summary> 142 /// <param name="level"></param> 143 private void RemovePanelItems(int level) 144 { 145 //判斷是否不是第一級 146 if (level < dropdownPanels.Count) 147 { 148 //點擊級之后的全部清除 149 for (int k = dropdownPanels.Count - 1; k >= level; k--) 150 { 151 for (int kk = dropdownPanels[k].transform.childCount - 1; kk >= 0; kk--) 152 { 153 Destroy(dropdownPanels[k].transform.GetChild(kk).gameObject); 154 } 155 //清除背景 156 Destroy(dropdownPanels[k].gameObject); 157 dropdownPanels.RemoveAt(k); 158 //保護防止越界 159 orderIndex = orderIndex >= 0 ? orderIndex : 0; 160 //清除位置 161 clickOrder[orderIndex] = 0; 162 orderIndex--; 163 //清除記錄按鈕 164 pointerButtonList.RemoveAt(k); 165 } 166 } 167 } 168 169 //設置按鈕顏色狀態 170 private void SetButtonState(Button button, ButtonColorState state) 171 { 172 Text buttonText = button.transform.Find("dropdownText").GetComponent<Text>(); 173 Image buttonArrow = button.transform.Find("dropdownArrow").GetComponent<Image>(); 174 if (state == ButtonColorState.Normal) 175 { 176 buttonText.color = new Color((111f / 256f), (111f / 256f), (111f / 256f), 1f); 177 buttonArrow.color = new Color((111f / 256f), (111f / 256f), (111f / 256f), 1f); 178 } 179 else if (state == ButtonColorState.Enter) 180 { 181 Color oldColor = buttonText.color; 182 buttonText.color = new Color(oldColor.r, oldColor.g, oldColor.b, (120f / 256f)); 183 buttonArrow.color = new Color(oldColor.r, oldColor.g, oldColor.b, (120f / 256f)); 184 } 185 else if (state == ButtonColorState.Exit) 186 { 187 Color oldColor = buttonText.color; 188 buttonText.color = new Color(oldColor.r, oldColor.g, oldColor.b, 1f); 189 buttonArrow.color = new Color(oldColor.r, oldColor.g, oldColor.b, 1f); 190 } 191 else if (state == ButtonColorState.Click) 192 { 193 buttonText.color = new Color((84f / 256f), (145f / 256f), (220f / 256f), 1f); 194 buttonArrow.color = new Color((84f / 256f), (145f / 256f), (220f / 256f), 1f); 195 } 196 } 197 198 //執行最終選中按鈕數據處理 199 private void OnSelectDropdownItem() 200 { 201 //記錄點擊位置 202 clickOrder[enterButtonLevel] = enterButtonInfo.index; 203 orderIndex = enterButtonLevel + 1; 204 if (enterButtonInfo.str != null) 205 { 206 ChangeMainText(enterButtonInfo.str); 207 } 208 else 209 { 210 List<IMoreDropdownInfo> nextList = enterButtonInfo.list; 211 nextList = enterButtonInfo.list; 212 RemovePanelItems(enterButtonLevel + 1); 213 CreateDropdown(enterButtonLevel + 1, nextList); 214 //處理選中按鈕狀態 215 if (pointerButtonList.Count >= enterButtonLevel) 216 SetButtonState(pointerButtonList[enterButtonLevel], ButtonColorState.Normal); 217 pointerButtonList[enterButtonLevel] = enterButton; 218 SetButtonState(enterButton, ButtonColorState.Click); 219 } 220 } 221 222 //隱藏 223 private void HideFirstPanel() 224 { 225 isShowFirstPanel = true; 226 hideBG.gameObject.SetActive(false); 227 RemovePanelItems(0); 228 orderIndex = 0; 229 } 230 231 //顯示 232 private void ShowFirstPanel() 233 { 234 isShowFirstPanel = true; 235 dropdownGrid.gameObject.SetActive(true); 236 } 237 238 //選好收回的Action回調 239 public Action<String, String> onClickItem; 240 //設置主按鈕的文字 241 private void ChangeMainText(String str) 242 { 243 Text firstText = mainButton.transform.Find("mainText").GetComponent<Text>(); 244 firstText.text = str; 245 //生成返回字符串 246 string orderStr = ""; 247 for (int i=0; i<orderIndex; i++) 248 { 249 if (i == 0) 250 { 251 orderStr += (clickOrder[i]+1); 252 } 253 else 254 { 255 orderStr += "|" + clickOrder[i]; 256 } 257 } 258 //隱藏所有並清空所有臨時數據 259 HideFirstPanel(); 260 //回調 261 onClickItem?.Invoke(str, orderStr); 262 } 263 264 //傳入值 265 public static void SetAllInfo(List<IMoreDropdownInfo> _allInfo) 266 { 267 allInfo = _allInfo; 268 } 269 }

 按鈕數據類

//按鈕數據
    public class IMoreDropdownInfo
    {
        //記錄位置
        public int index;
        //字符串或list
        public string str;
        public List<IMoreDropdownInfo> list;

        public IMoreDropdownInfo(String _str) { str = _str; }
        public IMoreDropdownInfo(List<IMoreDropdownInfo> _list) { list = _list; }
    }

按鈕數據生成類

//按鈕數據處理邏輯
    public class MoreDropdownItem
    {
        //創建一個獨立按鈕
        public static IMoreDropdownInfo CreateInfo(String str)
        {
            return new IMoreDropdownInfo(str);
        }

        //創建一個菜單
        public static List<IMoreDropdownInfo> CreateList()
        {
            List<IMoreDropdownInfo> _list = new List<IMoreDropdownInfo>();
            return _list;
        }

        //獨立按鈕添加到菜單中
        public static List<IMoreDropdownInfo> AddInfo(List<IMoreDropdownInfo> _list, IMoreDropdownInfo _info)
        {
            _info.index = _list.Count;
            _list.Add(_info);
            return _list;
        }

        //子級菜單添加到菜單中
        public static List<IMoreDropdownInfo> AddInfo(List<IMoreDropdownInfo> _list, List<IMoreDropdownInfo> _info)
        {
            IMoreDropdownInfo info = new IMoreDropdownInfo(_info);
            info.index = _list.Count;
            _list.Add(info);
            return _list;
        }

    }

Lua層數據處理

顯示數據

local textTable = {
    "全部",
    {
        "這是1",
        "這是2",
        "這是3",
        "這是4",
    },
    {
        "這是另一個1",
        "這是另一個2",
        "這是另一個3",
        "這是另一個4",
    },
}

生成菜單數據

function CreateDropdownStrTable(data)
    local itemList = MoreDropdownItem.CreateList()
    for i, v in ipairs(data) do
        if type(v) == "table" then
            local list = CreateDropdownStrTable(v)
            itemList = MoreDropdownItem.AddInfo(itemList, list)
        elseif type(v) == "string" then
            local info = MoreDropdownItem.CreateInfo(v)
            itemList = MoreDropdownItem.AddInfo(itemList, info)
        end
    end

    return itemList
end

實際使用

moreDropdown.onCreateDropdown = function()
    local strData = CreateDropdownStrTable(strTable)
    moreDropdown.SetAllInfo(strData)
end
moreDropdown.onClickItem = function(str, orderStr)
    --TODO
end

 

prefab

https://pan.baidu.com/s/1Ydt6goicLsN4jyPYwL7KUg

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM