Skip to content
This repository was archived by the owner on Jul 11, 2023. It is now read-only.

Commit 438a7b5

Browse files
committed
增加无线列表的脚本
1 parent ebfef4a commit 438a7b5

File tree

2 files changed

+393
-0
lines changed

2 files changed

+393
-0
lines changed
Lines changed: 382 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using UnityEngine;
5+
using UnityEngine.EventSystems;
6+
using UnityEngine.UI;
7+
8+
namespace Wanderer.GameFramework
9+
{
10+
public class InfiniteListView : UIBehaviour, IInitializePotentialDragHandler, IEventSystemHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IScrollHandler, ICanvasElement, ILayoutElement, ILayoutGroup, ILayoutController
11+
{
12+
13+
[SerializeField]
14+
private RectTransform _mask;
15+
16+
[SerializeField]
17+
private RectTransform _rendererItemPrefab;
18+
19+
[SerializeField]
20+
private int _columns = 2;
21+
22+
private Vector2 _itemSize;
23+
24+
[SerializeField]
25+
private float _spacing = 5.0f;
26+
27+
private List<InfiniteListItem> _items = new List<InfiniteListItem>();
28+
29+
private Vector2 _maskSize;
30+
31+
private Vector2 _dragMin = Vector2.zero;
32+
private Vector2 _dragMax = Vector2.zero;
33+
private Vector2 _dragPosition;
34+
private Vector2 _renderMin = Vector2.zero;
35+
private Vector2 _renderMax = Vector2.zero;
36+
37+
private float _maxHeight;
38+
39+
private List<RectTransform> _renderItems = new List<RectTransform>();
40+
private Queue<RectTransform> _rendererItemCachePool;
41+
42+
private Action<List<InfiniteListItem>> _onRenderItems;
43+
44+
protected override void Start()
45+
{
46+
base.Start();
47+
48+
Setup(60, () =>
49+
{
50+
StartCoroutine(TestItems(9999));
51+
}, (items) =>
52+
{
53+
foreach (var item in items)
54+
{
55+
item.RenderItem.transform.Find("Text").GetComponent<Text>().text = item.Id.ToString("d5");
56+
}
57+
});
58+
59+
}
60+
61+
62+
IEnumerator TestItems(int num)
63+
{
64+
for (int i = 0; i < num; i++)
65+
{
66+
yield return null;
67+
AddItem(1, UnityEngine.Random.Range(1.3f, 1.7f) * _itemSize.y);
68+
}
69+
//yield return new WaitForSeconds(5.0f);
70+
//for (int i = 0; i < 18; i++)
71+
//{
72+
// yield return new WaitForSeconds(1.0f);
73+
// AddItem(-1);
74+
//}
75+
}
76+
77+
public void Setup(int renderMax, Action cacheInstantiateComplete, Action<List<InfiniteListItem>> onRenderLists)
78+
{
79+
_maskSize = _mask.rect.size;
80+
_itemSize = _rendererItemPrefab.rect.size;
81+
_itemSize.y = _itemSize.x = (_maskSize.x - _spacing * (_columns + 1)) / _columns;
82+
//_spacing = (_maskSize.x - _itemSize.x * _itemColumns) / (_itemColumns + 1);
83+
Debug.Log($"InfiniteListView mask size: {_maskSize}. item prefab size: {_itemSize}. spacing: {_spacing}");
84+
_renderMin = new Vector2(0 - _itemSize.x, -_maskSize.y - _itemSize.y);
85+
_renderMax = new Vector2(_maskSize.x + _itemSize.x, 0 + _itemSize.y);
86+
_onRenderItems = onRenderLists;
87+
StartCoroutine(InstantiateRenderCache(renderMax, cacheInstantiateComplete));
88+
}
89+
90+
public InfiniteListView AddItem(int num = 1, float height = 0.0f)
91+
{
92+
if (num == 0)
93+
return this;
94+
95+
if (num > 0)
96+
{
97+
Vector2 startPos = _itemSize * 0.5f;
98+
if (_items.Count > 0)
99+
{
100+
startPos = _items[0].Size * 0.5f;
101+
}
102+
startPos += Vector2.one * _spacing;
103+
104+
int idIndex = _items.Count;
105+
for (int i = 0; i < num; i++)
106+
{
107+
int id = idIndex + i;
108+
InfiniteListItem item = new InfiniteListItem() { Id = id };
109+
int arrayIndex = id % _columns;
110+
int groupIndex = id / _columns;
111+
item.Size = new Vector2(_itemSize.x, height > 0.0f ? height : _itemSize.y);
112+
int lastId = id - _columns;
113+
if (lastId >= 0)
114+
{
115+
var lastItem = _items[lastId];
116+
startPos.y = lastItem.Position.y - lastItem.Size.y * 0.5f - _spacing - item.Size.y * 0.5f;
117+
}
118+
else
119+
{
120+
startPos.y = -item.Size.y * 0.5f - _spacing;
121+
}
122+
item.Position = new Vector2(startPos.x + arrayIndex * (_itemSize.x + _spacing), startPos.y);
123+
_items.Add(item);
124+
}
125+
}
126+
else if (num < 0)
127+
{
128+
num = Mathf.Abs(num);
129+
for (int i = 0; i < num; i++)
130+
{
131+
if (_items.Count > 0)
132+
{
133+
_items.RemoveAt(_items.Count - 1);
134+
}
135+
}
136+
}
137+
138+
_maxHeight = 0.0f;
139+
_dragMax = Vector2.zero;
140+
if (_items.Count > 0)
141+
{
142+
for (int i = _items.Count - 1; i >= _items.Count - _columns; i--)
143+
{
144+
if (i >= 0)
145+
{
146+
var lastItem = _items[i];
147+
float maxHeight = -lastItem.Position.y + lastItem.Size.y * 0.5f + _spacing;
148+
if (maxHeight > _maxHeight)
149+
{
150+
_maxHeight = maxHeight;
151+
}
152+
}
153+
}
154+
155+
_dragMax.y = _maxHeight - _maskSize.y;
156+
}
157+
158+
RebuildItemRenderer();
159+
return this;
160+
}
161+
162+
private void RebuildItemRenderer()
163+
{
164+
ClampDragPosition(10.0f);
165+
166+
if (_renderItems.Count > _items.Count)
167+
{
168+
for (int i = _items.Count; i < _renderItems.Count; i++)
169+
{
170+
RectTransform temp = _renderItems[i];
171+
temp.gameObject.SetActive(false);
172+
_rendererItemCachePool.Enqueue(temp);
173+
_renderItems.RemoveAt(i);
174+
i--;
175+
}
176+
}
177+
else
178+
{
179+
for (int i = _renderItems.Count; i < _items.Count; i++)
180+
{
181+
if (_rendererItemCachePool.Count > 0)
182+
{
183+
RectTransform temp = _rendererItemCachePool.Dequeue();
184+
temp.gameObject.SetActive(true);
185+
_renderItems.Add(temp);
186+
}
187+
else
188+
{
189+
break;
190+
}
191+
}
192+
}
193+
194+
foreach (var item in _renderItems)
195+
{
196+
item.gameObject.SetActive(false);
197+
}
198+
199+
int renderIndex = -1;
200+
201+
List<InfiniteListItem> renderItems = new List<InfiniteListItem>();
202+
203+
for (int i = 0; i < _items.Count; i++)
204+
{
205+
var item = _items[i];
206+
Vector2 renderPostion = _dragPosition + item.Position;
207+
208+
if (OutRenderBounds(renderPostion))
209+
{
210+
item.RenderItem = null;
211+
}
212+
else
213+
{
214+
renderIndex++;
215+
if (renderIndex < _renderItems.Count)
216+
{
217+
item.RenderItem = _renderItems[renderIndex];
218+
item.RenderItem.localPosition = renderPostion;
219+
item.RenderItem.sizeDelta = item.Size;
220+
item.RenderItem.gameObject.SetActive(true);
221+
renderItems.Add(item);
222+
}
223+
else
224+
{
225+
break;
226+
}
227+
}
228+
}
229+
230+
_onRenderItems?.Invoke(renderItems);
231+
}
232+
233+
private IEnumerator InstantiateRenderCache(int renderMax, Action cacheInstantiateComplete)
234+
{
235+
if (_rendererItemCachePool == null || _rendererItemCachePool.Count == 0)
236+
{
237+
_rendererItemCachePool = new Queue<RectTransform>();
238+
for (int i = 0; i < renderMax; i++)
239+
{
240+
GameObject clone = GameObject.Instantiate(_rendererItemPrefab.gameObject);
241+
clone.transform.SetParent(_mask.transform);
242+
clone.transform.localScale = Vector3.one;
243+
clone.SetActive(false);
244+
_rendererItemCachePool.Enqueue(clone.GetComponent<RectTransform>());
245+
yield return null;
246+
}
247+
}
248+
249+
cacheInstantiateComplete?.Invoke();
250+
}
251+
252+
253+
#region Interface
254+
public float minWidth => throw new System.NotImplementedException();
255+
256+
public float preferredWidth => throw new System.NotImplementedException();
257+
258+
public float flexibleWidth => throw new System.NotImplementedException();
259+
260+
public float minHeight => throw new System.NotImplementedException();
261+
262+
public float preferredHeight => throw new System.NotImplementedException();
263+
264+
public float flexibleHeight => throw new System.NotImplementedException();
265+
266+
public int layoutPriority => throw new System.NotImplementedException();
267+
268+
269+
#endregion
270+
271+
#region Interface
272+
273+
public void SetLayoutHorizontal()
274+
{
275+
//throw new System.NotImplementedException();
276+
}
277+
278+
public void SetLayoutVertical()
279+
{
280+
//throw new System.NotImplementedException();
281+
}
282+
283+
public void CalculateLayoutInputHorizontal()
284+
{
285+
//throw new System.NotImplementedException();
286+
}
287+
288+
public void CalculateLayoutInputVertical()
289+
{
290+
//throw new System.NotImplementedException();
291+
}
292+
293+
public void GraphicUpdateComplete()
294+
{
295+
//throw new System.NotImplementedException();
296+
}
297+
298+
public void LayoutComplete()
299+
{
300+
throw new System.NotImplementedException();
301+
}
302+
303+
public void OnBeginDrag(PointerEventData eventData)
304+
{
305+
//throw new System.NotImplementedException();
306+
}
307+
308+
public void OnDrag(PointerEventData eventData)
309+
{
310+
_dragPosition.y += eventData.delta.y;
311+
RebuildItemRenderer();
312+
}
313+
314+
public void OnEndDrag(PointerEventData eventData)
315+
{
316+
//throw new System.NotImplementedException();
317+
318+
ClampDragPosition();
319+
RebuildItemRenderer();
320+
}
321+
322+
public void OnInitializePotentialDrag(PointerEventData eventData)
323+
{
324+
//throw new System.NotImplementedException();
325+
}
326+
327+
public void OnScroll(PointerEventData eventData)
328+
{
329+
}
330+
331+
public void Rebuild(CanvasUpdate executing)
332+
{
333+
throw new System.NotImplementedException();
334+
}
335+
336+
#endregion
337+
338+
339+
private void ClampDragPosition(float floatDrag = 0.0f)
340+
{
341+
if (_maxHeight > _maskSize.y)
342+
{
343+
_dragPosition.x = Mathf.Clamp(_dragPosition.x, _dragMin.x - floatDrag, _dragMax.x + floatDrag);
344+
_dragPosition.y = Mathf.Clamp(_dragPosition.y, _dragMin.y - floatDrag, _dragMax.y + floatDrag);
345+
}
346+
else
347+
{
348+
_dragPosition = Vector2.zero;
349+
}
350+
Debug.Log($"_dragPosition: {_dragPosition} {_dragMin} {_dragMax}");
351+
}
352+
353+
private bool OutRenderBounds(Vector2 renderPosition)
354+
{
355+
if (renderPosition.x < _renderMin.x || renderPosition.x > _renderMax.x)
356+
return true;
357+
358+
if (renderPosition.y < _renderMin.y || renderPosition.y > _renderMax.y)
359+
return true;
360+
361+
return false;
362+
}
363+
364+
}
365+
366+
367+
368+
public struct InfiniteListItem
369+
{
370+
public int Id;
371+
public bool InRenderer
372+
{
373+
get
374+
{
375+
return RenderItem != null;
376+
}
377+
}
378+
public Vector2 Size;
379+
public Vector2 Position;
380+
public RectTransform RenderItem;
381+
}
382+
}

GameFramework/Runtime/UI/InfiniteListView.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)