using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; public class VirtualScrollRectPlus : ScrollRect { #region Config //上锁 解锁 对象池 需要外部实现 public Action OnVerticalLessEqual0; public Action OnVerticalGreaterEqual1; public Action OnHorizontalLessEqual0; public Action OnHorizontalGreaterEqual1; public Func GetNextItem; public Func GetPreviousItem; public Action OnSaveItem; public int FirstIndex; public int LastIndex; public bool Inited; public HorizontalOrVerticalLayoutGroup LayoutGroup; public int MaxRollAmount; public int MaxChildAmount; public bool NextPageLock; public bool PreviousPageLock; public List Children = new List(); public Dictionary ChildrenDataIndexDictionary = new Dictionary(); #endregion public override void OnDrag(PointerEventData eventData) { base.OnDrag(eventData); if (!Inited) { return; } if (horizontal && !vertical) { if (horizontalNormalizedPosition <= 0) { if (!PreviousPageLock) { Vector2 widthAndHeight = PreviousPage(); Roll(new Vector2(-widthAndHeight.x, 0)); } OnHorizontalGreaterEqual1.SafeInvoke(); } if (horizontalNormalizedPosition >= 1) { if (!NextPageLock) { Vector2 widthAndHeight = NextPage(); Roll(new Vector2(widthAndHeight.x, 0)); } OnHorizontalLessEqual0.SafeInvoke(); } } else if (!horizontal && vertical) { if (verticalNormalizedPosition >= 1) { if (!PreviousPageLock) { Vector2 widthAndHeight = PreviousPage(); Roll(new Vector2(0, widthAndHeight.y)); } OnVerticalGreaterEqual1.SafeInvoke(); } if (verticalNormalizedPosition <= 0) { if (!NextPageLock) { Vector2 widthAndHeight = NextPage(); Roll(new Vector2(0, -widthAndHeight.y)); } OnVerticalLessEqual0.SafeInvoke(); } } } public void Init(int maxRollAmount, int maxChildAmount, Func getNextItem, Func getPreviousItem, Action onSaveItem) { Inited = true; MaxRollAmount = maxRollAmount; MaxChildAmount = maxChildAmount; LayoutGroup = content.GetComponent(); GetNextItem = getNextItem; GetPreviousItem = getPreviousItem; OnSaveItem = onSaveItem; } public void SaveChild(VirtualScrollRectItem item) { int dataIndex = ChildrenDataIndexDictionary[item]; OnSaveItem.Invoke(dataIndex, item); Children.Remove(item); ChildrenDataIndexDictionary.Remove(item); if (Children.Count > 0) { FirstIndex = ChildrenDataIndexDictionary[Children[0]]; LastIndex = ChildrenDataIndexDictionary[Children.Back(0)]; } else { FirstIndex = 0; LastIndex = 0; } } public void SaveFirstChild() { SaveChild(Children[0]); } public void SaveLastChild() { SaveChild(Children.Back(0)); } public void InsertChild(int siblingIndex, int dataIndex, VirtualScrollRectItem item) { Children.Insert(siblingIndex, item); ChildrenDataIndexDictionary.Add(item, dataIndex); item.transform.SetSiblingIndex(siblingIndex); FirstIndex = ChildrenDataIndexDictionary[Children[0]]; LastIndex = ChildrenDataIndexDictionary[Children.Back(0)]; } public void InsertChildToFirst(int dataIndex, VirtualScrollRectItem item) { InsertChild(0, dataIndex, item); } public void InsertChildToLast(int dataIndex, VirtualScrollRectItem item) { InsertChild(Children.Count, dataIndex, item); } public Vector2 NextPage() { //Debug.LogWarning("NextPage"); List rolledItems = new List(); for (int i = 0; i < MaxRollAmount; i++) { int dataIndex = Children.Count == 0 ? 0 : LastIndex + 1; VirtualScrollRectItem item = GetNextItem.Invoke(dataIndex); if (item == null) { break; } else { if (Children.Count >= MaxChildAmount) { SaveFirstChild(); rolledItems.Add(item); } InsertChildToLast(dataIndex, item); } } Vector2 widthAndHeight = new Vector2(rolledItems.MySum(item => item.RectTransform.rect.width), rolledItems.MySum(item => item.RectTransform.rect.height)); widthAndHeight += new Vector2(LayoutGroup.spacing, LayoutGroup.spacing) * Mathf.Max(rolledItems.Count - 1, 0); return widthAndHeight; } public Vector2 PreviousPage() { //Debug.LogWarning("PreviousPage"); List rolledItems = new List(); for (int i = 0; i < MaxRollAmount; i++) { VirtualScrollRectItem item = GetPreviousItem.Invoke(FirstIndex-1); if (item == null) { break; } else { if (Children.Count >= MaxChildAmount) { SaveLastChild(); rolledItems.Add(item); } InsertChildToFirst(FirstIndex-1, item); } } Vector2 widthAndHeight = new Vector2(rolledItems.MySum(item => item.RectTransform.rect.width), rolledItems.MySum(item => item.RectTransform.rect.height)); widthAndHeight += new Vector2(LayoutGroup.spacing, LayoutGroup.spacing)*Mathf.Max(rolledItems.Count - 1, 0); return widthAndHeight; } public void Roll(Vector2 contentOffset) { m_ContentStartPosition += contentOffset; } }