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
}