zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    开启Android应用调试选项的工具XDebug的介绍
    Android Linker 与 SO 加壳技术
    PE文件格式偏移参考
    Android apk快速定位、灰色按钮克星--DroidSword
    Android系统加载Apk文件的时机和流程分析(1)--Android 4.4.4 r1的源码
    开启Android Apk调试与备份选项的Xposed模块的编写
    基于Xposed Hook实现的Android App的协议算法分析小工具-CryptoFucker
    排序学习之---选择排序
    在PHPStorm中快速插入当前日期
    排序学习之---插入排序
  • 原文地址:https://www.cnblogs.com/PandaQ/p/9945520.html
Copyright © 2011-2022 走看看