无线循环 ( 获取子节点、实现方法:添加头和尾,移除头和尾、添加简单数据库进行数据适配) LoopScrollView
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public enum LoopScrollViewType { Horizontal, Vertical } public class LoopScrollView : MonoBehaviour { #region 字段 //这是一个预制体,通过对它(GameObject)实例化来创建它的子物体 public GameObject childItemPrefab; public LoopScrollViewType scrollViewType = LoopScrollViewType.Vertical; private GridLayoutGroup contentLayoutGroup; private ContentSizeFitter sizeFitter; private RectTransform content; private DataApdater<LoopDataItem> dataApdater; #endregion #region Unity回调 //对字段进行初始化 private void Awake() { Init(); } private void Start() { //开始起到排序的作用 contentLayoutGroup.enabled = true; sizeFitter.enabled = true; //添加一个子节点 OnAddHead(); //禁用,在0.1秒后开始禁用 Invoke("EnableFalseGrid", 0.1f); } #endregion #region 方法 //初始化 public void Init() { content = transform.Find( "Viewport/Content").GetComponent<RectTransform>(); if (content == null) { throw new System.Exception(" content 初始化失败"); } contentLayoutGroup = content.GetComponent<GridLayoutGroup>(); if (contentLayoutGroup == null) { throw new System.Exception(" contentLayoutGroup 初始化失败"); } //判断是否获取到,若没有抛出异常 sizeFitter = content.GetComponent<ContentSizeFitter >(); if (sizeFitter == null) { throw new System.Exception(" sizeFitter 初始化失败"); } dataApdater = new DataApdater<LoopDataItem>(); //-----------------------------------测试模拟的数据------------------------------------------- List<LoopDataItem> loopDataItems = new List<LoopDataItem>(); for (int i = 0; i < 100; i++) { loopDataItems.Add(new LoopDataItem(i)); } dataApdater.InitData(loopDataItems); //初始化数据,将loopDataItems传递过去 //-------------------------------------------------------------------------------------- } //获取一个子节点 public GameObject GetChildItem() { //此原理为 对象池原理 //查找有没有 被回收 的子节点 (active 为 false 就是有被回收的子节点 ???) for (int i = 0; i < content.childCount ; i++) //for循环遍历出所有的子节点,判断所有的子节点有没有被回收 { if (!content.GetChild(i).gameObject.activeSelf) //!取反 所以现在状态是隐藏状态 { content.GetChild(i).gameObject.SetActive(true); return content.GetChild(i).gameObject; } } //如果没有 创建一个 GameObject childItem = GameObject.Instantiate(childItemPrefab, content.transform); //实例化一个游戏物体 子物体是childItemPrefab 父物体是content.transform childItem.transform.localScale = Vector3.one; //简单设置数据 大小、位置 childItem.transform.localPosition = Vector3.zero; childItem.GetComponent<RectTransform>().anchorMin = new Vector2(0, 1); //设置锚点 childItem.GetComponent<RectTransform>().anchorMax = new Vector2(0, 1); childItem.GetComponent<RectTransform>().sizeDelta = contentLayoutGroup.cellSize; //子物体 设置宽高 LoopItem loopItem = childItem.AddComponent<LoopItem>(); loopItem.onAddHead += this.OnAddHead; //??? loopItem.onRemoveHead += this.OnRemoveHead; loopItem.onAddLast += this.OnAddLast; loopItem.onRemoveLast += this.OnRemoveLast; loopItem.SetLoopScrollViewType(this.scrollViewType); return childItem ; } //在上面添加一个物体 public void OnAddHead() { LoopDataItem loopDataItem = dataApdater.GetHeaderData(); //获取同步数据 if ( loopDataItem != null ) { Debug.Log("添加头"); Transform first = FindFirst(); GameObject obj = GetChildItem(); //获取到一个子节点 obj.transform.SetAsFirstSibling(); //把它放在第一个位置 SetData(obj, loopDataItem); //设置数据 //动态设置位置 if (first != null) { switch (scrollViewType) { case LoopScrollViewType.Horizontal: obj.transform.localPosition = first.localPosition - new Vector3(contentLayoutGroup.cellSize.x + contentLayoutGroup.spacing.x, 0 , 0); break; case LoopScrollViewType.Vertical: obj.transform.localPosition = first.localPosition + new Vector3(0, contentLayoutGroup.cellSize.y + contentLayoutGroup.spacing.y, 0); break; } } } } //移除当前最上面的物体 public void OnRemoveHead() { Debug.Log("移除头"); if (dataApdater.RemoveHeadData()) { Transform first = FindFirst(); if (first != null) { first.gameObject.SetActive(false); } } } //在最后加一个物体 public void OnAddLast() { LoopDataItem loopDataItem = dataApdater.GetLastData(); //获取尾部数据 if (loopDataItem != null) { Debug.Log("添加尾"); Transform last = FindLast(); GameObject obj = GetChildItem(); //获取到一个子节点 obj.transform.SetAsLastSibling(); //把它放在最后位置 SetData(obj, loopDataItem); //设置数据 switch (scrollViewType) { case LoopScrollViewType.Horizontal: if (last != null) //动态设置位置 { obj.transform.localPosition = last.localPosition + new Vector3(contentLayoutGroup.cellSize.x + contentLayoutGroup.spacing.x, 0 , 0); } //要不要增加高度 if (IsNeedAddContentHeight(obj.transform)) { //对高度进行增加 content.sizeDelta += new Vector2(contentLayoutGroup.cellSize.x + contentLayoutGroup.spacing.x,0 ); //高度加间距 } break; case LoopScrollViewType.Vertical: if (last != null) //动态设置位置 { obj.transform.localPosition = last.localPosition - new Vector3(0, contentLayoutGroup.cellSize.y + contentLayoutGroup.spacing.y, 0); } //要不要增加高度 if (IsNeedAddContentHeight(obj.transform)) { //对高度进行增加 content.sizeDelta += new Vector2(0, contentLayoutGroup.cellSize.y + contentLayoutGroup.spacing.y); //高度加间距 } break; } } } //移除最后一个物体 public void OnRemoveLast() { if ( dataApdater.RemoveHeadData()) { Debug.Log("移出尾"); Transform last = FindLast(); if (last != null) { last.gameObject.SetActive(false); } } } //找到第一个游戏物体的位置 public Transform FindFirst() { for (int i = 0; i < content.childCount; i++) { if (content.GetChild(i).gameObject.activeSelf) { return content.GetChild(i); } } return null; } //找到最后一个游戏物体的位置 public Transform FindLast() { for (int i = content.childCount - 1; i >= 0 ; i--) { if (content.GetChild(i).gameObject.activeSelf) { return content.GetChild(i); } } return null; } //禁用 contentLayoutGroup sizeFitter 这两个组件 public void EnableFalseGrid() { contentLayoutGroup.enabled = false; sizeFitter.enabled = false; } //是不是需要增加 Content 的高度 ,类似于判断边界 public bool IsNeedAddContentHeight( Transform trans ) { Vector3[] rectCorners = new Vector3[4]; Vector3[] contentCorners = new Vector3[4]; trans.GetComponent<RectTransform>().GetWorldCorners(rectCorners); content.GetWorldCorners(contentCorners); switch (scrollViewType) { case LoopScrollViewType.Horizontal: if (rectCorners[3].x < contentCorners[3].x) { return true; } break; case LoopScrollViewType.Vertical: if (rectCorners[0].y < contentCorners[0].y) { return true; } break; } return false; } //设置数据 public void SetData(GameObject chileItem,LoopDataItem data) { chileItem.transform.Find("Text").GetComponent<Text>().text = data.id.ToString(); } #endregion }