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

  • 相关阅读:
    ASE19团队项目 beta阶段 model组 scrum report list
    ASE19团队项目 beta阶段 model组 scrum7 记录
    ASE19团队项目 beta阶段 model组 scrum6 记录
    ASE19团队项目 beta阶段 model组 scrum5 记录
    ASE19团队项目 beta阶段 model组 scrum4 记录
    ASE19团队项目 beta阶段 model组 scrum3 记录
    ASE19团队项目 beta阶段 model组 scrum2 记录
    ASE19团队项目 beta阶段 model组 scrum1 记录
    【ASE模型组】Hint::neural 模型与case study
    【ASE高级软件工程】第二次结对作业
  • 原文地址:https://www.cnblogs.com/PandaQ/p/9945520.html
Copyright © 2011-2022 走看看