UGUI DropDown遇到的问题总结

在使用UGUI的 DropDown 时, Canvas 的 Render Mode 选择了 Screen Space--Camera, 此时遇到一个小bug, 当我把这个下拉组件放到屏幕中间附近时, 下拉列表显示是正常的。当我把组件整体移到边缘,突然出现下拉列表的 Content 的坐标 不合法,由于 ugui 的点击关闭处理是在 Canvas 的子节点最下方又生成一个 全屏的 遮罩 来保证实现 “点击关闭”,所以此时整个界面卡死……翻遍源码断点我也没找到问题。


(中间:边缘)


另外,他的下拉列表实现, 不适合多个数据,假如有百十个就生成百十个下来的子菜单,这明显是不合理的,所以,把下拉改成 无限循环 列表是必须的。

于是,开始自己动手造轮子:
 
 
AخA
 
1
using System;  
2
using System.Collections;  
3
using System.Collections.Generic;  
4
using Assets.UI;  
5
using UnityEngine;  
6
using UnityEngine.UI;  
7
/// <summary>  
8
/// Introduction: GDropDown  
9
/// Author:     Cheng  
10
/// Time:   
11
/// </summary>  
12
[AddComponentMenu("UI/GDropdown", 100)]  
13
[RequireComponent(typeof(RectTransform))]  
14
public class GDropDown : MonoBehaviour  
15
  
16
    [Tooltip("Button of Whole Component")]  
17
    [SerializeField]  
18
    private Toggle m_CaptionToggle;  
19
    /// <summary>  
20
    /// Button of Whole Component  
21
    /// </summary>  
22
    public Toggle CaptionToggle  get  return m_CaptionToggle;  set  SetCaptionButton(value);   
23
    [Tooltip("Display Text of Selected Item")]  
24
    [SerializeField]  
25
    private Text m_CaptionText;  
26
    /// <summary>  
27
    /// Display Text of Selected Item  
28
    /// </summary>  
29
    public Text CaptionText  get  return m_CaptionText;  set  m_CaptionText = value;    
30
    [Tooltip("Display Image of Selected Item")]  
31
    [SerializeField]  
32
    private Image m_CaptionImage;  
33
    /// <summary>  
34
    /// Display Image of Selected Item  
35
    /// </summary>  
36
    public Image CaptionImage  get  return m_CaptionImage;  set  m_CaptionImage = value;    
37
    [Space]  
38
    [Tooltip("Drop List")]  
39
    [SerializeField]  
40
    private ScrollRect m_ScrollRect;  
41
    /// <summary>  
42
    /// Drop List   
43
    /// </summary>  
44
    public ScrollRect ScrollRect  get  return m_ScrollRect;  set  m_ScrollRect = value;    
45
    [Tooltip("Template of Drop List's Item")]     
46
    [SerializeField]  
47
    private GameObject m_DropItem;  
48
    /// <summary>  
49
    /// Template of Drop List's Item  
50
    /// </summary>  
51
    public GameObject DropItem  get  return m_DropItem;  set  SetDropItem(value);    
52
    [Tooltip("Current Select Index")]  
53
    [SerializeField]  
54
    private int m_Index;  
55
    /// <summary>  
56
    /// Current Select Index  
57
    /// </summary>  
58
    public int Index  get  return m_Index;  set  SetSelectIndex(value); }}  
59
    public string Text  get  return m_DropData.Count > Index ? m_DropData[Index].text : "";    
60
    /// <summary>  
61
    /// Drop Down Value Changed  
62
    /// </summary>  
63
    public Callback_1<int> OnValueChanged;  
64
    [Tooltip("Drop Data")]  
65
    [SerializeField]  
66
    List<GItemData> m_DropData = new List<GItemData>();  
67
    private ScrollList m_ScrollList;  
68
    private Dictionary<Transform, GItem> m_Items = new Dictionary<Transform, GItem>();  
69
    private RectTransform m_PointerMask;  
70
    private Transform m_Canvas;  
71
    void Awake()  
72
      
73
        m_ScrollList = GetOrAddComponent<ScrollList>(ScrollRect.gameObject);  
74
        m_ScrollList.onItemRender = OnItemRender;  
75
        SetSelectIndex(m_Index);  
76
        SetDropItem(m_DropItem);  
77
        RefreshShowValue();  
78
        SetCaptionButton(m_CaptionToggle);  
79
        m_CaptionToggle.isOn = false;  
80
        CloseMask();  
81
      
82
    public void AddOptions(string[] options)  
83
      
84
        for (int i = 0; i < options.Length; i++)  
85
            this.m_DropData.Add(new GItemData(options[i]));  
86
        if (m_CaptionToggle.isOn)  
87
            OpenMask();  
88
      
89
    public void AddOptions(Sprite[] options)  
90
      
91
        for (int i = 0; i < options.Length; i++)  
92
            this.m_DropData.Add(new GItemData(options[i]));  
93
        if (m_CaptionToggle.isOn)  
94
            OpenMask();  
95
      
96
    public void AddOptions(GItemData[] options)  
97
      
98
        for (int i = 0; i < options.Length; i++)  
99
            this.m_DropData.Add(options[i]);  
100
        if (m_CaptionToggle.isOn)  
101
            OpenMask();  
102
      
103
    public void RemoveAt(int index)  
104
      
105
        if (this.m_DropData.Count > index)  
106
          
107
            this.m_DropData.RemoveAt(index);  
108
            if (index == Index)  
109
              
110
                SetSelectIndex(index-1);  
111
              
112
          
113
      
114
    public void ClearOptions()  
115
      
116
        this.m_DropData.Clear();  
117
        if (m_CaptionToggle.isOn)  
118
            OpenMask();  
119
      
120
    /// <summary>  
121
    /// Refresh Display View  
122
    /// </summary>  
123
    private void RefreshShowValue()  
124
      
125
        if (m_DropData.Count > Index)  
126
          
127
            GItemData data = m_DropData[Index];  
128
            if (CaptionText != null)  
129
                CaptionText.text = data.text;  
130
            if (CaptionImage != null)  
131
                CaptionImage.sprite = data.image;  
132
          
133
        else  
134
          
135
            if (CaptionText != null)  
136
                CaptionText.text = "";  
137
            if (CaptionImage != null)  
138
                CaptionImage.sprite = null;  
139
          
140
      
141
    /// <summary>  
142
    /// Render Item in List  
143
    /// </summary>  
144
    /// <param name="index"></param>  
145
    /// <param name="child"></param>  
146
    private void OnItemRender(int index, Transform child)  
147
      
148
        GItem item;  
149
        if (!m_Items.TryGetValue(child, out item))  
150
            item = new GItem(this, child);  
151
        if (m_DropData.Count > index)  
152
          
153
            item.Reset(m_DropData[index].text, m_DropData[index].image, index == Index);  
154
          
155
      
156
    /// <summary>  
157
    /// Set Cur Select Index When Click  
158
    /// </summary>  
159
    /// <param name="p"></param>  
160
    internal void SetSelectIndex(int p)  
161
      
162
        if (p < m_DropData.Count) //if exist data  
163
          
164
            m_Index = p;  
165
            RefreshShowValue();  
166
            if (OnValueChanged != null)  
167
              
168
                OnValueChanged(m_Index);  
169
              
170
          
171
        else  
172
          
173
            if (m_DropData.Count > 0)//Back To First  
174
              
175
                m_Index = 0;  
176
                RefreshShowValue();  
177
                if (OnValueChanged != null)  
178
                  
179
                    OnValueChanged(m_Index);  
180
                  
181
              
182
          
183
        foreach (var value in m_Items.Values)  
184
          
185
            value.SetActive(false);  
186
          
187
        m_CaptionToggle.isOn = false;  
188
      
189
    /// <summary>  
190
    /// Open Mask to Poniters Out of List  
191
    /// </summary>  
192
    private void OpenMask()  
193
      
194
        if (m_PointerMask == null)//Create Mask  
195
          
196
            GameObject o = new GameObject("Pointer Mask");  
197
            o.transform.SetParent(transform);  
198
            Image mask = o.AddComponent<Image>();  
199
            mask.color = new Color(1, 1, 1, 0);  
200
            m_PointerMask = o.transform as RectTransform;  
201
            m_PointerMask.sizeDelta = new Vector2(Screen.width, Screen.height);  
202
            Button btnMask = o.AddComponent<Button>();  
203
            btnMask.onClick.AddListener(CloseMask);  
204
          
205
        if (m_Canvas == null)//Find Canvas  
206
          
207
            Canvas canvas = GameObject.FindObjectOfType<Canvas>();  
208
            m_Canvas = canvas.transform;  
209
          
210
        m_PointerMask.gameObject.SetActive(true);  
211
        m_PointerMask.SetParent(m_Canvas);  
212
        m_PointerMask.localPosition = Vector3.zero;  
213
        if (m_ScrollRect != null)  
214
          
215
            m_ScrollRect.transform.SetParent(m_Canvas);  
216
            m_ScrollRect.gameObject.SetActive(true);  
217
            m_ScrollList.ChildCount = m_DropData.Count;  
218
          
219
      
220
    /// <summary>  
221
    /// Close Mask to Other Pointers  
222
    /// </summary>  
223
    private void CloseMask()  
224
      
225
        if (m_PointerMask != null)  
226
          
227
            m_PointerMask.transform.SetParent(transform);  
228
            m_PointerMask.gameObject.SetActive(false);  
229
          
230
        if (m_ScrollRect != null)  
231
          
232
            m_ScrollRect.transform.SetParent(transform);  
233
            m_ScrollRect.gameObject.SetActive(false);  
234
          
235
      
236
    /// <summary>  
237
    /// Set Drop Item, Set Anchor Left-Top  
238
    /// </summary>  
239
    /// <param name="item"></param>  
240
    private void SetDropItem(GameObject item)  
241
      
242
        RectTransform rect = item.transform as RectTransform;  
243
        rect.anchorMin = Vector2.up;  
244
        rect.anchorMax = Vector2.up;  
245
        m_DropItem = item;  
246
        m_ScrollList.Child = item;  
247
      
248
    /// <summary>  
249
    /// Set Outter Button of Whole Component  
250
    /// </summary>  
251
    /// <param name="btn"></param>  
252
    private void SetCaptionButton(Toggle btn)  
253
      
254
        if (m_CaptionToggle != null)  
255
            m_CaptionToggle.onValueChanged.RemoveListener(OnCaptionButtonClicked);  
256
        m_CaptionToggle = btn;  
257
        if(m_CaptionToggle != null)  
258
            m_CaptionToggle.onValueChanged.AddListener(OnCaptionButtonClicked);  
259
      
260
    /// <summary>  
261
    /// On Caption Button Clicked  
262
    /// </summary>  
263
    private void OnCaptionButtonClicked(bool active)  
264
      
265
        if (active)  
266
            OpenMask();  
267
        else  
268
            CloseMask();  
269
      
270
    /// <summary>  
271
    /// Get Or Add Component on O  
272
    /// </summary>  
273
    /// <typeparam name="T"></typeparam>  
274
    /// <param name="o"></param>  
275
    /// <returns></returns>  
276
    T GetOrAddComponent<T>(GameObject o) where T : Component  
277
      
278
        T com = o.GetComponent<T>();  
279
        if (com == null)  
280
            com = o.AddComponent<T>();  
281
        return com;  
282
      
283
    /// <summary>  
284
    /// Release All  
285
    /// </summary>  
286
    public void OnDestroy()  
287
      
288
        //If Release on Drop State, Delete Mask  
289
        if(m_PointerMask != null)  
290
            m_PointerMask.SetParent(transform);  
291
      
292
    /// <summary>  
293
    /// Renderer Item in Endless List  
294
    /// </summary>  
295
    protected internal class GItem  
296
      
297
        GDropDown dropDown;  
298
        Transform item;  
299
        Button btn;  
300
        Text text;  
301
        Image image;  
302
        GameObject selected;  
303
        bool activeSelf;  
304
        public string m_Text  get  return text.text;  set  text.text = value;    
305
        public Sprite m_Image  get  return image.sprite;  set  image.sprite = value;    
306
        public GItem(GDropDown parent, Transform item)  
307
          
308
            this.dropDown = parent;  
309
            this.item = item;  
310
            activeSelf = false;  
311
            Transform t_trans = item.FindChild("text");  
312
            if (t_trans)  
313
              
314
                text = t_trans.gameObject.GetComponent<Text>();  
315
              
316
            Transform t_image = item.FindChild("image");  
317
            if (t_image)  
318
              
319
                image = t_image.gameObject.GetComponent<Image>();  
320
              
321
            Transform t_selected = item.FindChild("selected");  
322
            if (t_selected)  
323
              
324
                selected = t_selected.gameObject;  
325
              
326
            btn = item.GetComponent<Button>();  
327
            if (btn == null)  
328
              
329
                Transform t_btn = item.FindChild("btn");  
330
                if (t_btn != null)  
331
                    btn = dropDown.GetOrAddComponent<Button>(t_btn.gameObject);  
332
                else  
333
                    btn = dropDown.GetOrAddComponent<Button>(item.gameObject);  
334
              
335
            btn.onClick.AddListener(OnBtnItemClicked);  
336
          
337
        private void OnBtnItemClicked()  
338
          
339
            if (!activeSelf)  
340
              
341
                SetActive(true);  
342
                dropDown.SetSelectIndex(int.Parse(item.name));  
343
              
344
          
345
        internal void SetActive(bool active)  
346
          
347
            this.activeSelf = active;  
348
            if(selected != null)  
349
                selected.SetActive(active);  
350
          
351
        internal void Reset(string txt, Sprite sprite, bool active)  
352
          
353
            if (text != null)  
354
                m_Text = txt;  
355
            if (image != null)  
356
                m_Image = sprite;  
357
            SetActive(active);  
358
          
359
      
360
    /// <summary>  
361
    /// Cache Data  
362
    /// </summary>  
363
    [Serializable]  
364
    public class GItemData  
365
      
366
        [SerializeField]  
367
        private string m_Text;  
368
        [SerializeField]  
369
        private Sprite m_Image;  
370
        public string text   get  return m_Text;   set  m_Text = value;    
371
        public Sprite image  get  return m_Image;  set  m_Image = value;    
372
        public GItemData(){}  
373
        public GItemData(string text)  
374
          
375
            this.text = text;  
376
          
377
        public GItemData(Sprite image)  
378
          
379
            this.image = image;  
380
          
381
        public GItemData(string text, Sprite image)  
382
          
383
            this.text = text;  
384
            this.image = image;  
385
          
386
      
387
  

组件的点击由Toggle 来控制 与 系统UGUI的类似,支持 点击选中 图片和文字, 自己添加一个下拉列表。

注意: 下拉子选项中, 命名 “text”的“Text”组件、命名 “image”的“Image”组件为该选项的可填充值,看代码一眼便知。命名“selected”的表示下拉列表打开时该选项选中的表现,与toggle相同,我只是乐意改成了button表示而已。


www.nainaitea.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值