无线循环 ( 获取子节点、实现方法:添加头和尾,移除头和尾、添加简单数据库进行数据适配) 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
}

 

posted @ 2021-05-28 17:04  郭天真  阅读(127)  评论(0)    收藏  举报