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 OnGetNextItem; public Func OnGetPreviousItem; public Action OnSaveItem; public int FirstIndex; public int LastIndex; public bool Inited; public HorizontalOrVerticalLayoutGroup LayoutGroup; public int MaxRollAmount; public int MaxChildAmount; 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) { //Vector2 widthAndHeight = PreviousPage(); //Roll(new Vector2(-widthAndHeight.x, 0)); PreviousHorizontalPage(); OnHorizontalGreaterEqual1.SafeInvoke(); } if (horizontalNormalizedPosition >= 1) { //Vector2 widthAndHeight = NextPage(); //Roll(new Vector2(widthAndHeight.x, 0)); NextHorizontalPage(); OnHorizontalLessEqual0.SafeInvoke(); } } else if (!horizontal && vertical) { if (verticalNormalizedPosition >= 1) { //Vector2 widthAndHeight = PreviousPage(); //Roll(new Vector2(0, widthAndHeight.y)); PreviousVerticalPage(); OnVerticalGreaterEqual1.SafeInvoke(); } if (verticalNormalizedPosition <= 0) { //Vector2 widthAndHeight = NextPage(); //Roll(new Vector2(0, -widthAndHeight.y)); NextVerticalPage(); OnVerticalLessEqual0.SafeInvoke(); } } } public void Init(int maxRollAmount, int maxChildAmount, Func getNextItem = null, Func getPreviousItem = null, Action onSaveItem = null) { Inited = true; MaxRollAmount = maxRollAmount; MaxChildAmount = maxChildAmount; LayoutGroup = content.GetComponent(); OnGetNextItem = getNextItem; OnGetPreviousItem = getPreviousItem; OnSaveItem = onSaveItem; } public void SaveAllChild() { while (Children.Count > 0) { SaveFirstChild(); } } 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 VirtualScrollRectItem InsertChild(int siblingIndex, int dataIndex, VirtualScrollRectItem item, bool saveItem = false, int savaSiblingIndex = 0) { VirtualScrollRectItem savedItem = null; if (saveItem && Children.Count >= MaxChildAmount) { if (savaSiblingIndex == -1) { savedItem = Children.Back(0); } else { savedItem = Children[savaSiblingIndex]; } if (siblingIndex == Children.Count) { siblingIndex--; } SaveChild(savedItem); } Children.Insert(siblingIndex, item); ChildrenDataIndexDictionary.Add(item, dataIndex); item.transform.SetSiblingIndex(siblingIndex); FirstIndex = ChildrenDataIndexDictionary[Children[0]]; LastIndex = ChildrenDataIndexDictionary[Children.Back(0)]; return savedItem; } public VirtualScrollRectItem InsertChildToFirst(int dataIndex, VirtualScrollRectItem item, bool saveItem = false, int savaSiblingIndex = 0) { return InsertChild(0, dataIndex, item, saveItem, savaSiblingIndex); } public VirtualScrollRectItem InsertChildToLast(int dataIndex, VirtualScrollRectItem item, bool saveItem = false, int savaSiblingIndex = 0) { return InsertChild(Children.Count, dataIndex, item, saveItem, savaSiblingIndex); } public void NextVerticalPage() { Vector2 widthAndHeight = NextPage(); Roll(new Vector2(0, -widthAndHeight.y)); } public void NextHorizontalPage() { Vector2 widthAndHeight = NextPage(); Roll(new Vector2(widthAndHeight.x, 0)); } public void PreviousVerticalPage() { Vector2 widthAndHeight = PreviousPage(); Roll(new Vector2(0, widthAndHeight.y)); } public void PreviousHorizontalPage() { Vector2 widthAndHeight = PreviousPage(); Roll(new Vector2(-widthAndHeight.x, 0)); } private 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 = OnGetNextItem.Invoke(dataIndex); if (item == null) { break; } else { VirtualScrollRectItem savedItem = InsertChildToLast(dataIndex, item, true, 0); if (savedItem != null) { rolledItems.Add(savedItem); } } } 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; } private Vector2 PreviousPage() { //Debug.LogWarning("PreviousPage"); List rolledItems = new List(); for (int i = 0; i < MaxRollAmount; i++) { VirtualScrollRectItem item = OnGetPreviousItem.Invoke(FirstIndex-1); if (item == null) { break; } else { VirtualScrollRectItem savedItem = InsertChildToFirst(FirstIndex-1, item, true, -1); if (savedItem != null) { rolledItems.Add(savedItem); } } } 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; } }