【UGUI】踩坑填坑——DropDown
来源:互联网 发布:php好就业吗 编辑:程序博客网 时间:2024/06/03 06:48
在使用UGUI的 DropDown 时, Canvas 的Render Mode 选择了 Screen Space--Camera, 此时遇到一个小bug, 当我把这个下拉组件放到屏幕中间附近时, 下拉列表显示是正常的。当我把组件整体移到边缘,突然出现下拉列表的 Content 的坐标 不合法,由于 ugui 的点击关闭处理是在 Canvas 的子节点最下方又生成一个 全屏的 遮罩 来保证实现 "点击关闭",所以此时整个界面卡死..........翻遍源码断点我也没找到问题..
(中间:边缘)
另外,他的下拉列表实现, 不适合多个数据,假如有百十个就生成百十个下来的子菜单,这明显是不合理的,所以,把下拉改成 无限循环 列表是必须的。
于是,开始自己动手造轮子:
using System;using System.Collections;using System.Collections.Generic;using Assets.UI;using UnityEngine;using UnityEngine.UI;/// <summary>/// Introduction: GDropDown/// Author: Cheng/// Time: /// </summary>[AddComponentMenu("UI/GDropdown", 100)][RequireComponent(typeof(RectTransform))]public class GDropDown : MonoBehaviour{ [Tooltip("Button of Whole Component")] [SerializeField] private Toggle m_CaptionToggle; /// <summary> /// Button of Whole Component /// </summary> public Toggle CaptionToggle { get { return m_CaptionToggle; } set { SetCaptionButton(value);} } [Tooltip("Display Text of Selected Item")] [SerializeField] private Text m_CaptionText; /// <summary> /// Display Text of Selected Item /// </summary> public Text CaptionText { get { return m_CaptionText; } set { m_CaptionText = value; } } [Tooltip("Display Image of Selected Item")] [SerializeField] private Image m_CaptionImage; /// <summary> /// Display Image of Selected Item /// </summary> public Image CaptionImage { get { return m_CaptionImage; } set { m_CaptionImage = value; } } [Space] [Tooltip("Drop List")] [SerializeField] private ScrollRect m_ScrollRect; /// <summary> /// Drop List /// </summary> public ScrollRect ScrollRect { get { return m_ScrollRect; } set { m_ScrollRect = value; } } [Tooltip("Template of Drop List's Item")] [SerializeField] private GameObject m_DropItem; /// <summary> /// Template of Drop List's Item /// </summary> public GameObject DropItem { get { return m_DropItem; } set { SetDropItem(value); } } [Tooltip("Current Select Index")] [SerializeField] private int m_Index; /// <summary> /// Current Select Index /// </summary> public int Index { get { return m_Index; } set { SetSelectIndex(value); }} public string Text { get { return m_DropData.Count > Index ? m_DropData[Index].text : ""; } } /// <summary> /// Drop Down Value Changed /// </summary> public Callback_1<int> OnValueChanged; [Tooltip("Drop Data")] [SerializeField] List<GItemData> m_DropData = new List<GItemData>(); private ScrollList m_ScrollList; private Dictionary<Transform, GItem> m_Items = new Dictionary<Transform, GItem>(); private RectTransform m_PointerMask; private Transform m_Canvas; void Awake() { m_ScrollList = GetOrAddComponent<ScrollList>(ScrollRect.gameObject); m_ScrollList.onItemRender = OnItemRender; SetSelectIndex(m_Index); SetDropItem(m_DropItem); RefreshShowValue(); SetCaptionButton(m_CaptionToggle); m_CaptionToggle.isOn = false; CloseMask(); } public void AddOptions(string[] options) { for (int i = 0; i < options.Length; i++) this.m_DropData.Add(new GItemData(options[i])); if (m_CaptionToggle.isOn) OpenMask(); } public void AddOptions(Sprite[] options) { for (int i = 0; i < options.Length; i++) this.m_DropData.Add(new GItemData(options[i])); if (m_CaptionToggle.isOn) OpenMask(); } public void AddOptions(GItemData[] options) { for (int i = 0; i < options.Length; i++) this.m_DropData.Add(options[i]); if (m_CaptionToggle.isOn) OpenMask(); } public void RemoveAt(int index) { if (this.m_DropData.Count > index) { this.m_DropData.RemoveAt(index); if (index == Index) { SetSelectIndex(index-1); } } } public void ClearOptions() { this.m_DropData.Clear(); if (m_CaptionToggle.isOn) OpenMask(); } /// <summary> /// Refresh Display View /// </summary> private void RefreshShowValue() { if (m_DropData.Count > Index) { GItemData data = m_DropData[Index]; if (CaptionText != null) CaptionText.text = data.text; if (CaptionImage != null) CaptionImage.sprite = data.image; } else { if (CaptionText != null) CaptionText.text = ""; if (CaptionImage != null) CaptionImage.sprite = null; } } /// <summary> /// Render Item in List /// </summary> /// <param name="index"></param> /// <param name="child"></param> private void OnItemRender(int index, Transform child) { GItem item; if (!m_Items.TryGetValue(child, out item)) item = new GItem(this, child); if (m_DropData.Count > index) { item.Reset(m_DropData[index].text, m_DropData[index].image, index == Index); } } /// <summary> /// Set Cur Select Index When Click /// </summary> /// <param name="p"></param> internal void SetSelectIndex(int p) { if (p < m_DropData.Count) //if exist data { m_Index = p; RefreshShowValue(); if (OnValueChanged != null) { OnValueChanged(m_Index); } } else { if (m_DropData.Count > 0)//Back To First { m_Index = 0; RefreshShowValue(); if (OnValueChanged != null) { OnValueChanged(m_Index); } } } foreach (var value in m_Items.Values) { value.SetActive(false); } m_CaptionToggle.isOn = false; } /// <summary> /// Open Mask to Poniters Out of List /// </summary> private void OpenMask() { if (m_PointerMask == null)//Create Mask { GameObject o = new GameObject("Pointer Mask"); o.transform.SetParent(transform); Image mask = o.AddComponent<Image>(); mask.color = new Color(1, 1, 1, 0); m_PointerMask = o.transform as RectTransform; m_PointerMask.sizeDelta = new Vector2(Screen.width, Screen.height); Button btnMask = o.AddComponent<Button>(); btnMask.onClick.AddListener(CloseMask); } if (m_Canvas == null)//Find Canvas { Canvas canvas = GameObject.FindObjectOfType<Canvas>(); m_Canvas = canvas.transform; } m_PointerMask.gameObject.SetActive(true); m_PointerMask.SetParent(m_Canvas); m_PointerMask.localPosition = Vector3.zero; if (m_ScrollRect != null) { m_ScrollRect.transform.SetParent(m_Canvas); m_ScrollRect.gameObject.SetActive(true); m_ScrollList.ChildCount = m_DropData.Count; } } /// <summary> /// Close Mask to Other Pointers /// </summary> private void CloseMask() { if (m_PointerMask != null) { m_PointerMask.transform.SetParent(transform); m_PointerMask.gameObject.SetActive(false); } if (m_ScrollRect != null) { m_ScrollRect.transform.SetParent(transform); m_ScrollRect.gameObject.SetActive(false); } } /// <summary> /// Set Drop Item, Set Anchor Left-Top /// </summary> /// <param name="item"></param> private void SetDropItem(GameObject item) { RectTransform rect = item.transform as RectTransform; rect.anchorMin = Vector2.up; rect.anchorMax = Vector2.up; m_DropItem = item; m_ScrollList.Child = item; } /// <summary> /// Set Outter Button of Whole Component /// </summary> /// <param name="btn"></param> private void SetCaptionButton(Toggle btn) { if (m_CaptionToggle != null) m_CaptionToggle.onValueChanged.RemoveListener(OnCaptionButtonClicked); m_CaptionToggle = btn; if(m_CaptionToggle != null) m_CaptionToggle.onValueChanged.AddListener(OnCaptionButtonClicked); } /// <summary> /// On Caption Button Clicked /// </summary> private void OnCaptionButtonClicked(bool active) { if (active) OpenMask(); else CloseMask(); } /// <summary> /// Get Or Add Component on O /// </summary> /// <typeparam name="T"></typeparam> /// <param name="o"></param> /// <returns></returns> T GetOrAddComponent<T>(GameObject o) where T : Component { T com = o.GetComponent<T>(); if (com == null) com = o.AddComponent<T>(); return com; } /// <summary> /// Release All /// </summary> public void OnDestroy() { //If Release on Drop State, Delete Mask if(m_PointerMask != null) m_PointerMask.SetParent(transform); } /// <summary> /// Renderer Item in Endless List /// </summary> protected internal class GItem { GDropDown dropDown; Transform item; Button btn; Text text; Image image; GameObject selected; bool activeSelf; public string m_Text { get { return text.text; } set { text.text = value; } } public Sprite m_Image { get { return image.sprite; } set { image.sprite = value; } } public GItem(GDropDown parent, Transform item) { this.dropDown = parent; this.item = item; activeSelf = false; Transform t_trans = item.FindChild("text"); if (t_trans) { text = t_trans.gameObject.GetComponent<Text>(); } Transform t_image = item.FindChild("image"); if (t_image) { image = t_image.gameObject.GetComponent<Image>(); } Transform t_selected = item.FindChild("selected"); if (t_selected) { selected = t_selected.gameObject; } btn = item.GetComponent<Button>(); if (btn == null) { Transform t_btn = item.FindChild("btn"); if (t_btn != null) btn = dropDown.GetOrAddComponent<Button>(t_btn.gameObject); else btn = dropDown.GetOrAddComponent<Button>(item.gameObject); } btn.onClick.AddListener(OnBtnItemClicked); } private void OnBtnItemClicked() { if (!activeSelf) { SetActive(true); dropDown.SetSelectIndex(int.Parse(item.name)); } } internal void SetActive(bool active) { this.activeSelf = active; if(selected != null) selected.SetActive(active); } internal void Reset(string txt, Sprite sprite, bool active) { if (text != null) m_Text = txt; if (image != null) m_Image = sprite; SetActive(active); } } /// <summary> /// Cache Data /// </summary> [Serializable] public class GItemData { [SerializeField] private string m_Text; [SerializeField] private Sprite m_Image; public string text { get { return m_Text; } set { m_Text = value; } } public Sprite image { get { return m_Image; } set { m_Image = value; } } public GItemData(){} public GItemData(string text) { this.text = text; } public GItemData(Sprite image) { this.image = image; } public GItemData(string text, Sprite image) { this.text = text; this.image = image; } }}
组件的点击由Toggle 来控制 与 系统UGUI的类似,支持 点击选中 图片和文字, 自己添加一个下拉列表。
注意: 下拉子选项中, 命名 “text”的“Text”组件、命名 “image”的“Image”组件为该选项的可填充值,看代码一眼便知。命名“selected”的表示下拉列表打开时该选项选中的表现,与toggle相同,我只是乐意改成了button表示而已
Index 就是当前选中项,无限列表需要用到我以前文章中的一篇【UGUI】无限列表 ScrollView List
阅读全文
0 0
- 【UGUI】踩坑填坑——DropDown
- UGUI的Dropdown组件
- UGUI内核大探究(十三)Dropdown
- Unity3D UGUI中的dropdown控件使用总结
- UGUI 中Dropdown控件的使用经验
- UGUI Dropdown控件的大小设置
- UGUI内核大探究(十三)Dropdown
- UGUI提高<六> ToggleGroup勾选组和Dropdown下拉菜单
- [Unity][UGUI]DropDown下拉框监听改变值的事件
- Unity UGUI实现可编辑下拉框(dropdown)
- dropdown
- Unity—UGUI
- UGUI—Slider控制变量
- Bootstrap基础6——下拉菜单dropdown
- AjaxControltoolkit学习笔记—DropDown 使用详解 (asp.net C#)
- Unity UGUI——开源
- UGUI学习——Canvas
- UGUI学习——EventSystem
- 数据操作之《排序套餐:冒泡、选择、插入、快速、归并》
- 零基础深度学习笔记1——Ubuntu安装
- codevs 1205单词翻转
- .obj 和 .mtl文件格式
- PHP 多维数组
- 【UGUI】踩坑填坑——DropDown
- windows查看端口占用以及关闭相应的进程
- hive parquet table 配置使用压缩
- Linux下安装部署Java环境详解
- Android Fingerprint完全解析(一) :Fingerprint整体框架
- Oracle DB 使用单行函数定制输出
- 89. Gray Code [leetcode]
- 16:9
- 【怎样写代码】复杂对象的组装与创建 -- 建造者模式(一):问题案例