Tanoda
DropDownList.cs
Go to the documentation of this file.
1
3
4
5using System.Collections.Generic;
6
8{
12 [RequireComponent(typeof(RectTransform))]
13 [AddComponentMenu("UI/Extensions/Dropdown List")]
14 public class DropDownList : MonoBehaviour
15 {
17 public DropDownListItem SelectedItem { get; private set; } //outside world gets to get this, not set it
18
19 public List<DropDownListItem> Items;
20 public bool OverrideHighlighted = true;
21
22 //private bool isInitialized = false;
23 private bool _isPanelActive = false;
24 private bool _hasDrawnOnce = false;
25
26 private DropDownListButton _mainButton;
27
28 private RectTransform _rectTransform;
29
30 private RectTransform _overlayRT;
31 private RectTransform _scrollPanelRT;
32 private RectTransform _scrollBarRT;
33 private RectTransform _slidingAreaRT;
34 // private RectTransform scrollHandleRT;
35 private RectTransform _itemsPanelRT;
36 private Canvas _canvas;
37 private RectTransform _canvasRT;
38
39 private ScrollRect _scrollRect;
40
41 private List<DropDownListButton> _panelItems;
42
43 private GameObject _itemTemplate;
44
45 [SerializeField]
46 private float _scrollBarWidth = 20.0f;
47 public float ScrollBarWidth
48 {
49 get { return _scrollBarWidth; }
50 set
51 {
52 _scrollBarWidth = value;
53 RedrawPanel();
54 }
55 }
56
57 // private int scrollOffset; //offset of the selected item
58 private int _selectedIndex = -1;
59
60
61 [SerializeField]
62 private int _itemsToDisplay;
63 public int ItemsToDisplay
64 {
65 get { return _itemsToDisplay; }
66 set
67 {
68 _itemsToDisplay = value;
69 RedrawPanel();
70 }
71 }
72
73 public bool SelectFirstItemOnStart = false;
74
75 [System.Serializable]
76 public class SelectionChangedEvent : UnityEngine.Events.UnityEvent<int> {
77 }
78 // fires when item is changed;
80
81
82 public void Start()
83 {
84 Initialize();
85 if (SelectFirstItemOnStart && Items.Count > 0) {
86 ToggleDropdownPanel (false);
87 OnItemClicked (0);
88 }
89 }
90
91 private bool Initialize()
92 {
93 bool success = true;
94 try
95 {
96 _rectTransform = GetComponent<RectTransform>();
97 _mainButton = new DropDownListButton(_rectTransform.Find("MainButton").gameObject);
98
99 _overlayRT = _rectTransform.Find("Overlay").GetComponent<RectTransform>();
100 _overlayRT.gameObject.SetActive(false);
101
102
103 _scrollPanelRT = _overlayRT.Find("ScrollPanel").GetComponent<RectTransform>();
104 _scrollBarRT = _scrollPanelRT.Find("Scrollbar").GetComponent<RectTransform>();
105 _slidingAreaRT = _scrollBarRT.Find("SlidingArea").GetComponent<RectTransform>();
106 // scrollHandleRT = slidingAreaRT.FindChild("Handle").GetComponent<RectTransform>();
107 _itemsPanelRT = _scrollPanelRT.Find("Items").GetComponent<RectTransform>();
108 //itemPanelLayout = itemsPanelRT.gameObject.GetComponent<LayoutGroup>();
109
110 _canvas = GetComponentInParent<Canvas>();
111 _canvasRT = _canvas.GetComponent<RectTransform>();
112
113 _scrollRect = _scrollPanelRT.GetComponent<ScrollRect>();
114 _scrollRect.scrollSensitivity = _rectTransform.sizeDelta.y / 2;
115 _scrollRect.movementType = ScrollRect.MovementType.Clamped;
116 _scrollRect.content = _itemsPanelRT;
117
118
119 _itemTemplate = _rectTransform.Find("ItemTemplate").gameObject;
120 _itemTemplate.SetActive(false);
121 }
122 catch (System.NullReferenceException ex)
123 {
124 Debug.LogException(ex);
125 Debug.LogError("Something is setup incorrectly with the dropdownlist component causing a Null Reference Exception");
126 success = false;
127 }
128
129 _panelItems = new List<DropDownListButton>();
130
131 RebuildPanel();
132 RedrawPanel();
133 return success;
134 }
135
136 /* currently just using items in the list instead of being able to add to it.
137 public void AddItems(params object[] list)
138 {
139 List<DropDownListItem> ddItems = new List<DropDownListItem>();
140 foreach (var obj in list)
141 {
142 if (obj is DropDownListItem)
143 {
144 ddItems.Add((DropDownListItem)obj);
145 }
146 else if (obj is string)
147 {
148 ddItems.Add(new DropDownListItem(caption: (string)obj));
149 }
150 else if (obj is Sprite)
151 {
152 ddItems.Add(new DropDownListItem(image: (Sprite)obj));
153 }
154 else
155 {
156 throw new System.Exception("Only ComboBoxItems, Strings, and Sprite types are allowed");
157 }
158 }
159 Items.AddRange(ddItems);
160 Items = Items.Distinct().ToList();//remove any duplicates
161 RebuildPanel();
162 }
163 */
164
168 private void RebuildPanel()
169 {
170 if (Items.Count == 0) return;
171
172 int indx = _panelItems.Count;
173 while (_panelItems.Count < Items.Count)
174 {
175 GameObject newItem = Instantiate(_itemTemplate) as GameObject;
176 newItem.name = "Item " + indx;
177 newItem.transform.SetParent(_itemsPanelRT, false);
178
179 _panelItems.Add(new DropDownListButton(newItem));
180 indx++;
181 }
182 for (int i = 0; i < _panelItems.Count; i++)
183 {
184 if (i < Items.Count)
185 {
186 DropDownListItem item = Items[i];
187
188 _panelItems[i].txt.text = item.Caption;
189 if (item.IsDisabled) _panelItems[i].txt.color = disabledTextColor;
190
191 if (_panelItems[i].btnImg != null) _panelItems[i].btnImg.sprite = null;//hide the button image
192 _panelItems[i].img.sprite = item.Image;
193 _panelItems[i].img.color = (item.Image == null) ? new Color(1, 1, 1, 0)
194 : item.IsDisabled ? new Color(1, 1, 1, .5f)
195 : Color.white;
196 int ii = i; //have to copy the variable for use in anonymous function
197 _panelItems[i].btn.onClick.RemoveAllListeners();
198 _panelItems[i].btn.onClick.AddListener(() =>
199 {
200 OnItemClicked(ii);
201 if (item.OnSelect != null) item.OnSelect();
202 });
203 }
204 _panelItems[i].gameobject.SetActive(i < Items.Count);// if we have more thanks in the panel than Items in the list hide them
205 }
206 }
207
208 private void OnItemClicked(int indx)
209 {
210 //Debug.Log("item " + indx + " clicked");
211 if (indx != _selectedIndex && OnSelectionChanged != null) OnSelectionChanged.Invoke(indx);
212
213 _selectedIndex = indx;
215 UpdateSelected();
216 }
217
218 private void UpdateSelected()
219 {
220 SelectedItem = (_selectedIndex > -1 && _selectedIndex < Items.Count) ? Items[_selectedIndex] : null;
221 if (SelectedItem == null) return;
222
223 bool hasImage = SelectedItem.Image != null;
224 if (hasImage)
225 {
226 _mainButton.img.sprite = SelectedItem.Image;
227 _mainButton.img.color = Color.white;
228
229 //if (Interactable) mainButton.img.color = Color.white;
230 //else mainButton.img.color = new Color(1, 1, 1, .5f);
231 }
232 else
233 {
234 _mainButton.img.sprite = null;
235 }
236
237 _mainButton.txt.text = SelectedItem.Caption;
238
239 //update selected index color
241 {
242
243 for (int i = 0; i < _itemsPanelRT.childCount; i++)
244 {
245 _panelItems[i].btnImg.color = (_selectedIndex == i) ? _mainButton.btn.colors.highlightedColor : new Color(0, 0, 0, 0);
246 }
247 }
248 }
249
250
251 private void RedrawPanel()
252 {
253 float scrollbarWidth = Items.Count > ItemsToDisplay ? _scrollBarWidth : 0f;//hide the scrollbar if there's not enough items
254
255 if (!_hasDrawnOnce || _rectTransform.sizeDelta != _mainButton.rectTransform.sizeDelta)
256 {
257 _hasDrawnOnce = true;
258 _mainButton.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
259 _mainButton.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _rectTransform.sizeDelta.y);
260 _mainButton.txt.rectTransform.offsetMax = new Vector2(4, 0);
261
262 _scrollPanelRT.SetParent(transform, true);//break the scroll panel from the overlay
263 _scrollPanelRT.anchoredPosition = new Vector2(0, -_rectTransform.sizeDelta.y); //anchor it to the bottom of the button
264
265 //make the overlay fill the screen
266 _overlayRT.SetParent(_canvas.transform, false); //attach it to top level object
267 _overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _canvasRT.sizeDelta.x);
268 _overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _canvasRT.sizeDelta.y);
269
270 _overlayRT.SetParent(transform, true);//reattach to this object
271 _scrollPanelRT.SetParent(_overlayRT, true); //reattach the scrollpanel to the overlay
272 }
273
274 if (Items.Count < 1) return;
275
276 float dropdownHeight = _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, Items.Count);
277
278 _scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
279 _scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
280
281 _itemsPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _scrollPanelRT.sizeDelta.x - scrollbarWidth - 5);
282 _itemsPanelRT.anchoredPosition = new Vector2(5, 0);
283
284 _scrollBarRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, scrollbarWidth);
285 _scrollBarRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
286
287 _slidingAreaRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 0);
288 _slidingAreaRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight - _scrollBarRT.sizeDelta.x);
289 }
290
295 public void ToggleDropdownPanel(bool directClick)
296 {
297 _overlayRT.transform.localScale = new Vector3(1, 1, 1);
298 _scrollBarRT.transform.localScale = new Vector3(1, 1, 1);
299 _isPanelActive = !_isPanelActive;
300 _overlayRT.gameObject.SetActive(_isPanelActive);
301 if (_isPanelActive)
302 {
303 transform.SetAsLastSibling();
304 }
305 else if (directClick)
306 {
307 // scrollOffset = Mathf.RoundToInt(itemsPanelRT.anchoredPosition.y / _rectTransform.sizeDelta.y);
308 }
309 }
310 }
311}
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
UnityEngine.Color Color
Definition: TestScript.cs:32
Extension to the UI class which creates a dropdown list
Definition: DropDownList.cs:15
void ToggleDropdownPanel(bool directClick)
Toggle the drop down list
SelectionChangedEvent OnSelectionChanged
Definition: DropDownList.cs:79
List< DropDownListItem > Items
Definition: DropDownList.cs:19
Sprite Image
Image component of the Item
Credit Erdener Gonenc - @PixelEnvision.