一 基础类 在unity里面新建这几个类
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 垂直方向滚动
/// </summary>
public class CustomScroll:MonoBehaviour
{public ScrollRect scrollRect;protected List<object> list = new();private RectTransform contentRect;private GridLayoutGroup layoutGroup;public GameObject item;private List<CustomScrollItemMono> scrollTestItems = new();private CustomVertial customVertial;private int startIndex;private int endIndex;private int showItemCount = 14;private void Awake(){contentRect = scrollRect.content.GetComponent<RectTransform>();layoutGroup = contentRect.GetComponent<GridLayoutGroup>();customVertial = contentRect.GetComponent<CustomVertial>();scrollRect.horizontal = false;scrollRect.vertical = true;scrollRect.onValueChanged.AddListener((value) =>{layoutGroup.enabled = false;customVertial.enabled = false;for (int i = startIndex; i < itemPosList.Count; i++){var y = contentRect.anchoredPosition3D.y;if (i + layoutGroup.constraintCount < itemPosList.Count) {if (scrollRect.velocity.y > 0)//手指上滑 {var targetY = -itemPosList[i + layoutGroup.constraintCount].y;if (y >= targetY){startIndex = i + layoutGroup.constraintCount;endIndex = startIndex + showItemCount - layoutGroup.constraintCount;break;}}else if (scrollRect.velocity.y < 0)//手指下滑{if (startIndex > 0 && startIndex < itemPosDic.Count) {var targetY = -itemPosDic[startIndex].y;if (y <= targetY){startIndex = i - layoutGroup.constraintCount;endIndex = startIndex + showItemCount - layoutGroup.constraintCount;break;}}}}}Debug.Log($"bbb startIndex {startIndex} endIndex {endIndex}");if (endIndex >= itemPosDic.Count) { return; }int index = 0;for (int i = startIndex; i < endIndex + layoutGroup.constraintCount; i++){if (index < scrollTestItems.Count && i < itemPosDic.Count) {var item = scrollTestItems[index];item.Init(i, list[i]);var rect = item.gameObject.GetComponent<RectTransform>();rect.anchoredPosition3D = itemPosDic[i];index += 1;}}});}private Dictionary<int, Vector3> itemPosDic = new();private List<Vector3> itemPosList = new();public void Init() {InitListData();InitItemsPos();InitContentSize();InitShowItems();}public virtual void InitListData() {//必须要新建类 继承此类 重写此方法设置数据}private void InitItemsPos() {int prevRow = 0;int initIndex = 0;for (int i = 0; i < list.Count; i++){int row = Mathf.CeilToInt((i + 1) * 1f / layoutGroup.constraintCount);var pos = Vector3.zero;if (row != prevRow){pos = new Vector3(0, -((row - 1) * (layoutGroup.cellSize.y + layoutGroup.spacing.y) + layoutGroup.padding.top));initIndex = 0;}else{initIndex += 1;pos = new Vector3(initIndex * (layoutGroup.cellSize.x + layoutGroup.spacing.x) + layoutGroup.padding.left, -((row - 1) * (layoutGroup.cellSize.y + layoutGroup.spacing.y) + layoutGroup.padding.top));}itemPosList.Add(pos);itemPosDic.Add(i, pos);prevRow = row;}}private void InitContentSize() {float width = layoutGroup.padding.left + layoutGroup.cellSize.x * layoutGroup.constraintCount +(layoutGroup.constraintCount - 1) * layoutGroup.spacing.x;float height = layoutGroup.padding.top + layoutGroup.cellSize.y * Mathf.Ceil(itemPosList.Count / layoutGroup.constraintCount) +itemPosList.Count / layoutGroup.constraintCount * layoutGroup.spacing.y;contentRect.sizeDelta = new Vector2(width, height);customVertial.SetSize(new Vector2(width, height));}private void InitShowItems() {for (int i = 0; i < showItemCount; i++){GameObject obj = Instantiate(item, contentRect);RectTransform rect = obj.GetComponent<RectTransform>();rect.anchorMin = new Vector2(0, 1);rect.anchorMax = new Vector2(0, 1);rect.pivot = new Vector2(0, 1);obj.transform.name = i.ToString();obj.SetActive(true);CustomScrollItemMono testItem = obj.GetComponent<CustomScrollItemMono>();testItem.Init(i, list[i]);scrollTestItems.Add(testItem);}item.SetActive(false);}
}public class ScrollTestData
{public int ID;
}
using System.Collections.Generic;
using UnityEngine;public interface ICustomScrollItem
{public void Init(int index,object data);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;//这个类一定要挂在GridLayout下面 控制Content尺寸
public class CustomVertial : ContentSizeFitter
{private Vector2 size = new();private RectTransform rectTransform;protected override void Awake(){base.Awake();rectTransform = GetComponent<RectTransform>();}public void SetSize(Vector2 s) {size = s;}public override void SetLayoutVertical(){base.SetLayoutVertical();rectTransform.sizeDelta = size;}
}
using System.Collections.Generic;
using UnityEngine;public class CustomScrollItemMono : MonoBehaviour,ICustomScrollItem
{public void Init(int index, object data){InitView(index, data);}public virtual void InitView(int index, object data) {}
}
二 具体使用实例类
1.挂在ScrollRect组件下面 在面板上设置好Scroll和Content和子元素Item
重写了InitListData 方法 设置需要的列表数据 这里测试放在Start里面启动列表
实际根据具体逻辑启动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CustomScrollTest:CustomScroll
{public override void InitListData(){base.InitListData();for (int i = 0; i < 100; i++){list.Add(new ScrollTestData() { ID = i });}}private void Start(){Init();}
}
2.具体的Item元素类 挂在Item上
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class ScrollTestItem : CustomScrollItemMono
{public Text text;private ScrollTestData Data= new();private int Index;public override void InitView(int index, object data){ScrollTestData testData = (ScrollTestData)data;Index = index;Data = testData;text.text = Index.ToString();transform.name = Index.ToString();}
}