ScrollRect面板实现简单的横向动态有限数量内的循环简单案例

/*--------------------------------------------------------------------

  • Author Name: DXL
  • Creation Time: 2018.10.26
  • File Describe: ScrollRect面板实现简单的横向动态有限数量内的循环
  • ------------------------------------------------------------------*/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InfinityLoop : MonoBehaviour
{
#region 变量

//注意,最后的实际数量为 minAmount + 2,因为Grid下面原来就有一个
public int minAmount = 10;           //一次加载最少的物体数量,从0开始计数,


RectTransform rectTrans;            //当前Grid的RectTransform
HorizontalLayoutGroup layoutGroup;  //Grid上挂载的网格控件
ContentSizeFitter fitter;           //Grid挂载的自适应控件
ScrollRect scroll;                  //滚动面板控件

List<RectTransform> children = new List<RectTransform>();   //存放子物体位置
Vector2 startPosition;              //存放拖动时开始位置
int amount;                         //生成物体的总数量,打开界面一瞬间就固定好了,就是按钮总数量
int realIndex = -1;                 //物体序号

float gridChildWidth;               //Grid下要实例化的物体宽度
float gridChildHeight;              //Grid下要实例化的物体高度

//拖动结束后的委托
public delegate void UpdateChildrenCallbackDelegate(int index, Transform trans);
public UpdateChildrenCallbackDelegate updateChildrenCallback = null;

#endregion

#region 方法

void InitComponent()
{
    rectTrans = GetComponent<RectTransform>();
    layoutGroup = GetComponent<HorizontalLayoutGroup>();
    fitter = GetComponent<ContentSizeFitter>();
    scroll = transform.parent.GetComponent<ScrollRect>();


    gridChildWidth = transform.GetChild(0).GetComponent<RectTransform>().sizeDelta.x;
    gridChildHeight = transform.GetChild(0).GetComponent<RectTransform>().sizeDelta.y;
    //注册ScrollRect滚动回调;
    scroll = transform.parent.GetComponent<ScrollRect>();
    scroll.onValueChanged.AddListener((data) => { ScrollCallback(data); });
}

IEnumerator InitChildren()
{
    //等一帧
    yield return 0;

    InitComponent();

    //获取对应子物体的信息
    for (int i = 0; i < transform.childCount; ++i)
    {
        Transform trans = transform.GetChild(i);
        trans.gameObject.SetActive(true);
        children.Add(transform.GetChild(i).GetComponent<RectTransform>());

        //初始化前面几个;
        UpdateChildrenCallback(children.Count - 1, transform.GetChild(i));
    }

    //获取初始位置
    startPosition = rectTrans.anchoredPosition;
    realIndex = children.Count - 1;

    //显示规定数量以内的物体
    for (int i = 0; i < minAmount; ++i)
    {
        children[i].gameObject.SetActive(i < amount);
    }



}


void ScrollCallback(Vector2 data)
{
    UpdateChildren();
}

//更新物体信息,参数 当前物体生成的序号,对应物体的位置信息
void UpdateChildrenCallback(int index, Transform trans)
{
    if (updateChildrenCallback != null)
    {
        updateChildrenCallback(index, trans);
    }
}

//更新物体(核心)
void UpdateChildren()
{
    if (transform.childCount < minAmount)
    {
        return;
    }

    Vector2 currentPos = rectTrans.anchoredPosition;

    //原来是一个一个移动,现在要4个一起移动,这里就先增加3个物体的宽度
    float offsetWidth = gridChildWidth * 3;
    //Grid位置最左边的位置超过移动刚开始的位置偏移了多少
    float offsetX = currentPos.x - startPosition.x;
    //float offsetX = currentPos.x - startPosition.x + offsetWidth;

    //向左滑动,向右扩展(物体从屏幕右边向中间移动)
    if (offsetX < 0)  
    {
        //如果当前生成的物体数量已经达到规定上限,就不再继续生成(向右扩展时到头了)
        if (realIndex >= amount - 1)
        {
            startPosition = currentPos;
            return;
        }

        //将scroll的位置转换成世界坐标,得到移动面板(固定scroll)的左边界点位置
        //float scrollLeft = scroll.transform.TransformPoint(Vector3.zero).x;
        float scrollLeft = Camera.main.WorldToScreenPoint(scroll.transform.position).x;
        //检测的子物体的序号,原来是0,即第一个(最左边那个),现在先换成3,第4个试试
        int checkChildIndex = 0;
        //children[0].anchoredPosition 就是实例化后的物体第一个物体的相对坐标
        //1、
        //Vector3 childBottomRight = new Vector3(children[checkChildIndex].anchoredPosition.x + gridChildWidth,
        //    children[checkChildIndex].anchoredPosition.y, 0);
        //2、
        Vector3 childBottomRight = new Vector3(children[checkChildIndex].gameObject.transform.position.x + gridChildWidth,
            children[checkChildIndex].gameObject.transform.position.y, 0);
        //3、
        //RectTransformUtility.WorldToScreenPoint()
        //Canvas canvas = scroll.transform.parent.parent.GetComponent<Canvas>();
        //GameObject obj = children[checkChildIndex].gameObject;
        //Vector3 scr = RectTransformUtility.WorldToScreenPoint(canvas.worldCamera, obj.transform.position);
        //scr.z = 0;
        //scr.z = Mathf.Abs(Camera.main.transform.position.z - transform.position.z);
        //Vector3 changeVec = Camera.main.ScreenToWorldPoint(scr);
        //4、
        //Vector3[] vecs = new Vector3[4];
        //children[checkChildIndex].GetWorldCorners(vecs);
        //5、
        //Vector3 childBottomRight = new Vector3(children[checkChildIndex].sizeDelta.x + gridChildWidth,
        //    children[checkChildIndex].sizeDelta.y, 0);

        //将最左边的子物体x的坐标转换成世界坐标,(用于比较,判断是否跑到屏幕外面(左边)去了)
        //float childRight = transform.TransformPoint(childBottomRight).x;
        float childRight = Camera.main.WorldToScreenPoint(childBottomRight).x;
        //Debug.Log("child width " + gridChildWidth);
        //Debug.Log("scroll pos " + scroll.transform.position);
        //Debug.Log("0: " + vecs[0] + ", 1: " + vecs[1] + ", 2: " + vecs[2] + ", 3: " + vecs[3]);
        //Debug.Log("child1 pos " + children[checkChildIndex].gameObject.transform.position);
        //Debug.Log("child2 pos " + children[1].gameObject.transform.position);
        //Debug.Log("new child world pos " + changeVec);
        //Debug.Log("scroll " + scrollLeft + " , childRight is " + childRight);
        //最左边的物体已经被完全被拉到屏幕左边去了,就是最左边的这个物体已经看不见了
        if (childRight <= scrollLeft)
        {
            //要将看不见的这个物体移动到最右边去,如果是多行,这里要有个for循环,将每一行都进行这种操作

            //将首个物体的循序放到路径的最下面
            children[checkChildIndex].SetAsLastSibling();
            //将它的位置移动到当前子物体最后一个物体的右边,y值保持不变间隔为0,就不加
            children[checkChildIndex].anchoredPosition = new Vector2(children[children.Count - 1].anchoredPosition.x
                + gridChildWidth, children[checkChildIndex].anchoredPosition.y);

            //相当于新增了一个物体,最新的物体序号+1
            realIndex++;


            //更新最新的物体信息
            UpdateChildrenCallback(realIndex, children[checkChildIndex]);
        }

        //生成物体后,HorizontalLayoutGroup右边要加成对应长度
        rectTrans.sizeDelta += new Vector2(gridChildWidth, 0);

        //更新child数组
        for (int i = 0; i < children.Count; ++i)
        {
            children[i] = transform.GetChild(i).GetComponent<RectTransform>();
        }
    }

    //向右滑动,向左扩展,(物体从屏幕左边向中间移动)
    else
    {
        //如果向左移动到头了,就停止移动了
        if (realIndex + 1 <= children.Count)
        {
            startPosition = currentPos;
            return;
        }

        RectTransform scrollRect = scroll.GetComponent<RectTransform>();
        Vector3 scrollAnchorRight = new Vector3(scrollRect.rect.width, 0, 0);
        float scrollRight = scrollRect.transform.TransformPoint(scrollAnchorRight).x;
        Vector3 childLeftPos = new Vector3(children[children.Count - 1].anchoredPosition.x,
            children[children.Count - 1].anchoredPosition.y, 0);

        float childLeft = transform.TransformPoint(childLeftPos).x;

        if (childLeft >= scrollRight) //物体已经被滑动到屏幕最右边看不见的地方了
        {
            //将最后一个物体移动到子物体首个位置上
            children[children.Count - 1].SetAsFirstSibling();
            children[children.Count - 1].anchoredPosition = new Vector2(children[0].anchoredPosition.x - gridChildWidth,
                children[0].anchoredPosition.y);
            children[children.Count - 1].gameObject.SetActive(true);

            UpdateChildrenCallback(realIndex - children.Count, children[children.Count - 1]);
        }

        rectTrans.sizeDelta -= new Vector2(gridChildWidth, 0);
        for (int i = 0; i < children.Count; ++i)
        {
            children[i] = transform.GetChild(i).GetComponent<RectTransform>();
        }

        realIndex--;
    }

    //每次移动之后,更新一下起始点的位置信息
    startPosition = currentPos;
}

public void SetAmount(int count)
{
    amount = count;
    StartCoroutine(InitChildren());
}


#endregion

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值