美文网首页
Unity scrollRect 无限滚动实现

Unity scrollRect 无限滚动实现

作者: Charon_ted | 来源:发表于2019-05-07 15:45 被阅读0次

    首先是竖直下拉,效果如下:

    效果图

    其中的minAmount是显示最少需要的个数,个数是整个屏幕最多能放下的个数+1 比如效果中,最多能放下三组,所以设置的是4(这里因为显示效果一行三个为1组 使用1哥prefab)

    然后在 scrollRect的 connect组建中 需要使用如下组件


    image.png

    当前是竖向下拉 所以在GridGroupConnect中需要把 constraint 按照如下设置 在content size fitter中设置为竖向为最佳尺寸

    然后是横向翻页的效果

    5555.gif
    image.png

    connect的设置如下

    需要注意的是 当时为了方便计算 在使用时需要将 image.png

    prefab 进行如下设置

    image.png

    prefab的所有父物体(到scrollrect为止 包括scrollrect)的pivot 也要试着为0 1 这样操作是为了计算式统一通过左上角进行计算 如果有其他需求可修改计算过程中的具体代码

    代码如下:

    using UnityEngine;
    using System.Collections.Generic;
    using UnityEngine.UI;
    using System.Collections;
    //lsh 
    public class InfinityPackgeTool : MonoBehaviour
    {
    
        public enum Axies
        {
            horizontal = 0,
            vertical = 1
        }
    
        public int minAmount;
        public ScrollRect scrollRect;
        public Transform itemPrefab;
    
        public delegate void UpdateChildrenCallBack(int index, Transform trans);
        public UpdateChildrenCallBack updateChildrenDelegate = null;
    
        private GameObject scrollContent;
        private GridLayoutGroup gridLayoutGroup;
        private ContentSizeFitter contentSizeFitter;
    
        private List<RectTransform> childTransList;
        private Dictionary<Transform, int> childStartIndexDic;
        private Dictionary<int, Vector2> childStartAnchordPosition;
    
        private Vector2 connectStartSize;
        private Vector2 connectStartAnchordPos;
        private int childItemNum;
        private int realEndIndex = -1;
        private int amount;
        private RectTransform rectTransform;
        private RectTransform scrollRectTrans;
        private Vector2 lastPosition;
        private Vector2 gridLayoutStartSize;
        private Axies axies;
    
        private bool isNeedAutoChangeConnectScale;
        private bool isRegistEvent = false;
    
    
        /// <summary>
        /// 
        /// </summary>
        /// <param name="num">item的数量</param>
        /// <param name="isNeedAutoChangeScale">是否需要自动修改大小 若为true则直接设置为最大大小并不自动更改 否则根据当前位置自动更改connect大小</param>
        public void SetAmount(int num,bool isNeedAutoChangeScale)
        {
            amount = num;
            isNeedAutoChangeConnectScale = isNeedAutoChangeScale;
            StartCoroutine(InitManager());
        }
    
        IEnumerator InitManager()
        {
            if (!isRegistEvent)
            {
                for (int i = 0; i < minAmount; i++)
                {
                    GameObject g = Instantiate(itemPrefab).gameObject;
                    g.transform.SetParent(itemPrefab.transform.parent);
                    g.transform.localScale = Vector3.one;
                    g.SetActive(true);
                }
                Destroy(itemPrefab.gameObject);
            }
            yield return 0;//wait for a flame
            //first open
    
            if (!isRegistEvent)
            {
                isRegistEvent = true;
    
                scrollContent = scrollRect.content.gameObject;
                rectTransform = scrollContent.GetComponent<RectTransform>();
                gridLayoutGroup = scrollContent.GetComponent<GridLayoutGroup>();
                contentSizeFitter = scrollContent.GetComponent<ContentSizeFitter>();
                connectStartSize = scrollContent.GetComponent<RectTransform>().sizeDelta;
                lastPosition = rectTransform.anchoredPosition;
                gridLayoutStartSize = rectTransform.sizeDelta;
                connectStartAnchordPos = rectTransform.anchoredPosition;
    
                scrollRectTrans = scrollRect.GetComponent<RectTransform>();
    
                gridLayoutGroup.enabled = false;
                contentSizeFitter.enabled = false;
                axies = Axies.vertical;
                if (gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedRowCount)
                    axies = Axies.horizontal;
    
                childItemNum = scrollContent.transform.childCount;
    
                childTransList = new List<RectTransform>();
                childStartIndexDic = new Dictionary<Transform, int>();
                childStartAnchordPosition = new Dictionary<int, Vector2>();
                for (int index = 0; index < childItemNum; index++)
                {
                    Transform t = scrollContent.transform.GetChild(index);
                    childTransList.Add(t.GetComponent<RectTransform>());
                    childStartIndexDic.Add(t, index);
                    childStartAnchordPosition.Add(index, t.GetComponent<RectTransform>().anchoredPosition);
                }
                if(!isNeedAutoChangeConnectScale)
                {
                    int pageNum = amount / gridLayoutGroup.constraintCount + ((amount % gridLayoutGroup.constraintCount == 0) ? 0 : 1);
                    if (axies == Axies.horizontal)
                    {
                        scrollContent.GetComponent<RectTransform>().sizeDelta = new Vector2(gridLayoutGroup.cellSize.x * pageNum + gridLayoutGroup.spacing.x * (pageNum - 1) + gridLayoutGroup.padding.left+gridLayoutGroup.padding.right, scrollContent.GetComponent<RectTransform>().sizeDelta.y);
                        //scrollRect.horizontalNormalizedPosition = 0;
                    }
                    else
                    {
                        scrollContent.GetComponent<RectTransform>().sizeDelta = new Vector2(scrollContent.GetComponent<RectTransform>().sizeDelta.x, gridLayoutGroup.cellSize.y * pageNum + gridLayoutGroup.spacing.y * (pageNum - 1) + gridLayoutGroup.padding.top + gridLayoutGroup.padding.bottom);
                        //scrollRect.verticalNormalizedPosition = 1;
                    }
                }
                scrollRect.onValueChanged.AddListener(UpdateChildren);
            }
            else
            {
                //reset all data
                if (isNeedAutoChangeConnectScale)
                    scrollContent.GetComponent<RectTransform>().sizeDelta = connectStartSize;
                else
                {
                    int pageNum = amount / gridLayoutGroup.constraintCount + ((amount % gridLayoutGroup.constraintCount == 0) ? 0 : 1);
                    if (axies == Axies.horizontal)
                    {
                        scrollContent.GetComponent<RectTransform>().sizeDelta = new Vector2(gridLayoutGroup.cellSize.x * pageNum + gridLayoutGroup.spacing.x * (pageNum - 1) + gridLayoutGroup.padding.left + gridLayoutGroup.padding.right, scrollContent.GetComponent<RectTransform>().sizeDelta.y);
                    }
                    else
                    {
                        scrollContent.GetComponent<RectTransform>().sizeDelta = new Vector2(scrollContent.GetComponent<RectTransform>().sizeDelta.x, gridLayoutGroup.cellSize.y * pageNum + gridLayoutGroup.spacing.y * (pageNum - 1) + gridLayoutGroup.padding.top + gridLayoutGroup.padding.bottom);
                    }
                }
                scrollContent.GetComponent<RectTransform>().anchoredPosition = connectStartAnchordPos;
                childTransList.Clear();
                foreach (var d in childStartIndexDic)
                {
                    d.Key.SetSiblingIndex(d.Value);
                    d.Key.GetComponent<RectTransform>().anchoredPosition = childStartAnchordPosition[d.Value];
                    childTransList.Add(d.Key.GetComponent<RectTransform>());
                }
            }
            //init data
            int num = amount;
            if (childItemNum < amount)
                num = childItemNum;
            for (int index = 0; index < childItemNum; index++)
            {
                if (index < amount)
                {
                    updateChildrenDelegate(index, childTransList[index]);
                    childTransList[index].gameObject.SetActive(true);
                }
                else
                {
                    childTransList[index].gameObject.SetActive(false);
                }
    
            }
            realEndIndex = childItemNum-1;
        }
    
        public void AcheivementRemovePhotoUpdate(int pageNum)
        {
            //移动到目标页数
            for (int index = 0; index <= pageNum; index++)
            {
                lastPosition.x = 0;
                UpdateChildren(Vector2.zero);
            }
        }
    
        private void UpdateChildren(Vector2 v)
        {
            if (scrollContent.transform.childCount < minAmount)
                return;
    
            Vector2 currentPos = rectTransform.anchoredPosition;
            //is horizontal slide
            if (axies == Axies.horizontal)
            {
                float offset = currentPos.x - lastPosition.x;
                //connct move direct : right ,right column move to left
                if (offset > 0)
                {
                    //is slide to connect buttom,return
                    if (realEndIndex <= childItemNum - 1)
                    {
                        lastPosition = currentPos;
                        return;
                    }
                    
                    float scrollRectRight = scrollRect.transform.TransformPoint(new Vector3(scrollRectTrans.rect.width + gridLayoutGroup.spacing.x, 0, 0)).x;
    
                    //is last item left line x pos more than scrollLeft x pos plus gridGroupLayout spacing x pos
                    Vector3 childLastColunmLeft = new Vector3(childTransList[childItemNum - 1].anchoredPosition.x + gridLayoutGroup.spacing.x - gridLayoutGroup.cellSize.x * childTransList[childItemNum - 1].pivot.x, 0, 0);//need to add spacing
                    float childLeft =scrollContent.transform.TransformPoint(childLastColunmLeft).x;
    
                    if (childLeft >= scrollRectRight)
                    {
                        //right column move to left
                        for (int index = 0; index <gridLayoutGroup.constraintCount ; index++)
                        {
                            childTransList[childItemNum - 1 - index].anchoredPosition = new Vector2(childTransList[0].anchoredPosition.x - gridLayoutGroup.spacing.x - gridLayoutGroup.cellSize.x, childTransList[childItemNum - 1 - index].anchoredPosition.y);
                            childTransList[childItemNum - 1 - index].SetAsFirstSibling();
                            updateChildrenDelegate(realEndIndex - childItemNum - index, childTransList[childItemNum - 1 - index]);
                            childTransList[childItemNum - 1 - index].gameObject.SetActive(true);
                        }
                        if (isNeedAutoChangeConnectScale)//need to minus spacing
                            scrollContent.GetComponent<RectTransform>().sizeDelta -= new Vector2(gridLayoutGroup.spacing.x + gridLayoutGroup.cellSize.x, 0);
    
                        realEndIndex -= gridLayoutGroup.constraintCount;
                    }
    
                }
                else//connect move direct : left,left column to right
                {
                    if (realEndIndex >= amount-1)
                    {
                        lastPosition = currentPos;
                        return;
                    }
                    float scrollRectLeft = scrollRect.transform.TransformPoint(Vector3.zero).x;
    
                    Vector3 childStartColumnRight = new Vector3(childTransList[0].anchoredPosition.x + gridLayoutGroup.cellSize.x * (1 - childTransList[0].pivot.x), 0f, 0f);
                    float childRight = scrollContent.transform.TransformPoint(childStartColumnRight).x;
    
                    if (childRight <= scrollRectLeft)
                    {
                        for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                        {
                            childTransList[index].anchoredPosition = new Vector2(childTransList[childItemNum - 1 - index].anchoredPosition.x + gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x, childTransList[index].anchoredPosition.y);
                            childTransList[index].SetAsLastSibling();
                            realEndIndex++;
                            if (realEndIndex >= amount)
                            {
                                childTransList[index].gameObject.SetActive(false);
                            }
                            else
                            {
                                updateChildrenDelegate(realEndIndex, childTransList[index]);
                            }
                        }
                        if (isNeedAutoChangeConnectScale)//need to minus spacing
                            scrollContent.GetComponent<RectTransform>().sizeDelta += new Vector2(gridLayoutGroup.spacing.x + gridLayoutGroup.cellSize.x, 0);
                    }
                }
            }
            else //same as horizontal
            {
                float offset = currentPos.y - lastPosition.y;
                if (offset > 0)//connect mode direct : up,top row move to buttom
                {
                    if (realEndIndex >= amount - 1)
                    {
                        lastPosition = currentPos;
                        return;
                    }
                    float scrollRectTop = scrollRect.transform.TransformPoint(Vector3.zero).y;
                    float childTopRowButtom = scrollContent.transform.TransformPoint(new Vector3(0, childTransList[0].anchoredPosition.y - gridLayoutGroup.cellSize.y * (1-childTransList[0].pivot.y) - gridLayoutGroup.spacing.y, 0)).y;
    
                    if (scrollRectTop < childTopRowButtom)
                    {
                        for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                        {
                            childTransList[index].transform.SetAsLastSibling();
                            childTransList[index].anchoredPosition = new Vector2(childTransList[index].anchoredPosition.x, childTransList[childItemNum - 1 ].anchoredPosition.y - gridLayoutGroup.spacing.y - gridLayoutGroup.cellSize.y);
                            realEndIndex++;
                            if (realEndIndex >= amount)
                            {
                                childTransList[index].gameObject.SetActive(false);
                            }
                            else
                            {
                                updateChildrenDelegate(realEndIndex, childTransList[index]);
                            }
                        }
    
                        if(isNeedAutoChangeConnectScale)
                            scrollContent.GetComponent<RectTransform>().sizeDelta += new Vector2(0, gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);
                    }
                }
                else//connect move direct down,buttom row move to top
                {
                    if (realEndIndex <= childItemNum - 1)
                    {
                        lastPosition = currentPos;
                        return;
                    }
                    float scrollRectButtom = scrollRect.transform.TransformPoint(new Vector3(0,-scrollRectTrans.rect.height,0)).y;
                    float childButtomRowTop = scrollContent.transform.TransformPoint(new Vector3(0, childTransList[childItemNum - 1].anchoredPosition.y + gridLayoutGroup.cellSize.y * childTransList[childItemNum - 1].pivot.y, 0)).y;
                    if (childButtomRowTop <= scrollRectButtom)
                    {
                        for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                        {
                            childTransList[childItemNum - 1 - index].anchoredPosition = new Vector2(childTransList[childItemNum - 1 - index].anchoredPosition.x, childTransList[0].anchoredPosition.y + gridLayoutGroup.spacing.y + gridLayoutGroup.cellSize.y);
                            childTransList[childItemNum - 1 - index].SetAsFirstSibling();
                            childTransList[childItemNum - 1 - index].gameObject.SetActive(true);
                            updateChildrenDelegate(realEndIndex - childItemNum - index, childTransList[childItemNum - 1 - index]);
                        }
                        realEndIndex -= gridLayoutGroup.constraintCount;
    
                        if (isNeedAutoChangeConnectScale)
                            scrollContent.GetComponent<RectTransform>().sizeDelta -= new Vector2(0, gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);
                    }
                }
    
            }
            lastPosition = currentPos;
            //update child list
            for (int index = 0; index < childItemNum; index++)
            {
                childTransList[index] = scrollContent.transform.GetChild(index).GetComponent<RectTransform>();
            }
    
        }
    
    }
    
    

    相关文章

      网友评论

          本文标题:Unity scrollRect 无限滚动实现

          本文链接:https://www.haomeiwen.com/subject/haweoqtx.html