unity 常规无限滚动的使用需要注意的几个地方(坑!)

无限滚动是很常用的一个东西,平时设置好就没再管过, 偶尔用到的时候缺被几个小坑绊了一跤, 总结如下:

1,也是最基本的一点 数量要设置对;如下图

2.挂在脚本的物体要稍稍大于cell的数量

不然滑动的时候会出现各种恶心的状况 比如拉上去又弹回来什么的

3.写代码的时候 更要注意 几点:

 void CreateHBlist(Dictionary<string, string> dic)
    {
        Sql<HouseYZList>(_HttpType.Get, WD._url + "style/getStuffList", list =>
        {
            HouseYZList = list.result;
            InitHouseYZList();
        }, dic);
    }
    public List<YZInfo> HouseYZList = new List<YZInfo>();
    int amount ;//Content下最多能容纳的格子数量
    private InfinityGridLayoutGroup YZGrid;
    void InitHouseYZList()
    {
        YZGrid = gameObject.FindDeepChild("Panel_Scroll/Panel_Grid").GetComponent<InfinityGridLayoutGroup>();
        YZGrid.SetAmount(HouseYZList.Count);
        amount = HouseYZList.Count;//一定要设置这个数量!
        YZGrid.updateChildrenCallback = Update_YZGrid;
    }
    /// <summary>
    /// 无限滚动列表回调
    /// </summary>
    /// <param name="index"></param>
    /// <param name="trans"></param>
    void Update_YZGrid(int index, Transform trans)
    {
        if (amount == 0) return;
        index = index % amount;
        RawImage raw = trans.gameObject.GetComponent<RawImage>();
        DestroyImmediate(raw.texture, true);
        zz_wd_CacheManager.ins.LoadImage(HouseYZList[index].previewUrl, tex => { raw.texture = tex; });
        _3D_YZPage_Item item = trans.GetComponent<_3D_YZPage_Item>();
        item.data = HouseYZList[index];
        item.MyType = NowType;
    }

4.如果滑动的时候卡顿  可以将最大数量多设置几个 提前加载就不会卡了

最后奉上我用的这个无限滚动的代码

 

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

[RequireComponent(typeof(GridLayoutGroup))]//网格布局
[RequireComponent(typeof(ContentSizeFitter))]//自适应
public class InfinityGridLayoutGroup : MonoBehaviour 
{
    [SerializeField]
    int minAmount = 0;//实现无限滚动,需要的最少的child数量。屏幕上能看到的+一行看不到的,比如我在屏幕上能看到 2 行,每一行 2 个。则这个值为 2行*2个 + 1 行* 2个 = 6个。
    RectTransform rectTransform;
    GridLayoutGroup gridLayoutGroup;
    ContentSizeFitter contentSizeFitter;

    ScrollRect scrollRect;//滚动框

    List<RectTransform> children=new List<RectTransform>();

    Vector2 startPosition;//开始锚点位置

    int amount = 0;

    public delegate void UpdateChildrenCallbackDelegate(int index, Transform trans);
    public UpdateChildrenCallbackDelegate updateChildrenCallback = null;

    int realIndex = -1;
   // int realIndexUp = -1; //从下往上;

    bool hasInit = false;//是否初始化过
    Vector2 gridLayoutSize;
    Vector2 gridLayoutPos;
    //存储Gird的锚点集合<child的index,锚点位置>
    Dictionary<Transform, Vector2> childsAnchoredPosition = new Dictionary<Transform, Vector2>();
    //存储Gird的节点在所有兄弟节点中的位置<序号index,节点位置>
    Dictionary<Transform, int> childsSiblingIndex = new Dictionary<Transform, int>();
    IEnumerator InitChildren()
    {
        yield return 0;
        ///没有初始化进行初始化   并获得相应的组件设置锚点和调整锚点的大小增量   
        ///给父体添加滚动框组件   并给滚动框添加回调点击事件   
        ///遍历每一个孩子获取每一孩子的角标  使得每个自孩子添加<RectTransform>锚点位置组件
        ///获取Gird的锚点位置以及节点   
        if (!hasInit)//如果没有初始化
        {
            //获取Grid的宽度;
            rectTransform = GetComponent<RectTransform>();

            gridLayoutGroup = GetComponent<GridLayoutGroup>();
            gridLayoutGroup.enabled = false;
            contentSizeFitter = GetComponent<ContentSizeFitter>();
            contentSizeFitter.enabled = false;
            //锚点位置
            gridLayoutPos = rectTransform.anchoredPosition;
            //大小增量:矩阵变换的大小相对于锚点之间的距离。 
            gridLayoutSize = rectTransform.sizeDelta;
      
            //注册ScrollRect滚动回调;
            scrollRect = transform.parent.GetComponent<ScrollRect>();//给盒子的父物体添加ScrollRect滚动框组件
            scrollRect.onValueChanged.AddListener((data) => { ScrollCallback(data);});

            //获取所有child anchoredPosition 以及 SiblingIndex;
            for (int index = 0; index < transform.childCount; index++)
            {
                Transform child=transform.GetChild(index);
                RectTransform childRectTrans= child.GetComponent<RectTransform>();
                childsAnchoredPosition.Add(child, childRectTrans.anchoredPosition);

                childsSiblingIndex.Add(child, child.GetSiblingIndex());
            }
        }
        else
        {
            rectTransform.anchoredPosition = gridLayoutPos;
            rectTransform.sizeDelta = gridLayoutSize;

            children.Clear();

            realIndex = -1;
           // realIndexUp = -1;

            //children重新设置上下顺序;
            foreach (var info in childsSiblingIndex)
            {
                info.Key.SetSiblingIndex(info.Value);
            }

            //children重新设置anchoredPosition;
            for (int index = 0; index < transform.childCount; index++)
            {
                Transform child = transform.GetChild(index);
                
                RectTransform childRectTrans = child.GetComponent<RectTransform>();
                if (childsAnchoredPosition.ContainsKey(child))
                {
                    childRectTrans.anchoredPosition = childsAnchoredPosition[child];
                }
                else
                {
                    Debug.Log("childsAnchoredPosition no contain "+child.name);
                }
            }
        }

        //获取所有child;
        for (int index = 0; index < transform.childCount; index++)
        {
            Transform trans = transform.GetChild(index);
            trans.gameObject.SetActive(true);

            children.Add(transform.GetChild(index).GetComponent<RectTransform>());
            //children.Add(Transform.GetChild(index).GetChild(1).GetComponent<Text>);

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

        startPosition = rectTransform.anchoredPosition;

        realIndex = children.Count - 1;

        //Debug.Log( scrollRect.transform.TransformPoint(Vector3.zero));

       // Debug.Log(transform.TransformPoint(children[0].localPosition));

        hasInit = true;

        //如果需要显示的个数小于设定的个数;
        for (int index = 0; index < minAmount; index++)
        {
            children[index].gameObject.SetActive(index < amount);
            //Debug.Log("第" + index + "个Gird, " + "minAmount个数为" + minAmount);
        }
        //如果纵向排列 设置的最小Grid数量和所需要显示的Grid数量对比结果进行锚框的高度设置
        if (gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount)
        {
            //如果小了一行,则需要把GridLayout的高度减去一行的高度;
            int row = (minAmount - amount) / gridLayoutGroup.constraintCount;
            //Debug.Log("Row的值为" + row);
            if (row > 0)
            {
                rectTransform.sizeDelta -= new Vector2(0, (gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y) * row);
            }
        }
        //否则横向排列 对锚框进行宽的设置
        else
        {
            //如果小了一列,则需要把GridLayout的宽度减去一列的宽度;
            int column = (minAmount - amount) / gridLayoutGroup.constraintCount;
            if (column > 0)
            {
                rectTransform.sizeDelta -= new Vector2((gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x) * column, 0);
            }
        }
    }
    void ScrollCallback(Vector2 data)
    {
        UpdateChildren();
    }

    //刷新子物体
    void UpdateChildren()
    {
        //如果挂有滚动框组件物体的孩子数量小于设定的最小数量
        if (transform.childCount < minAmount) return;
        Vector2 currentPos = rectTransform.anchoredPosition;//获取当前锚点位置
        //设置滑动方向
        if (gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount)
        {
            float offsetY = currentPos.y - startPosition.y;//纵向滑动偏移量

            if (offsetY > 0)
            {
                //向上拉,向下扩展;
                {
                    if (realIndex >= amount - 1)
                    {
                        startPosition = currentPos;
                        return;
                    }
                    //**************************核心算法********************************//
                    //主要是通过获得Panel_Scroll的锚点PosY的值,这是不变的,因为开始设置的即是屏幕的高1080
                    //再通过他的子物体格子的PoxY,由于格子的锚点定的是居于Content的左上角,所以这里记录为childBottomLeft
                    //通过获得Panel_Grid.y的世界坐标Y即是Panel_Scroll的位置,此时与Panel_Scroll的恒定值1080对比
                    //通过对比childBottom与恒定的1080值
                    //当格子走过的路径大于等于1080时设置格子的层级SetAsLastSibling

                    //调整布局
                    //transform.TransformPoint 变换位置从局部坐标到世界坐标。
                    //获得Panel_Scroll的RectTransform PosY=1080
                    float scrollRectUp = scrollRect.transform.TransformPoint(Vector3.zero).y;
                    //纵向滑动改变的只是格子锚点的PosY
                    Vector3 childBottomLeft = new Vector3(children[0].anchoredPosition.x, children[0].anchoredPosition.y - gridLayoutGroup.cellSize.y, 0f);    
                    float childBottom = transform.TransformPoint(childBottomLeft).y;
                    //Debug.Log("scrollRectUp====" + scrollRectUp);
                    //Debug.Log("childBottomLeft===" + childBottomLeft);
                    //Debug.Log("childBottom====" + childBottom);
                    if (childBottom >= scrollRectUp)
                    {
                        //Debug.Log("childBottom >= scrollRectUp");

                        //移动到底部;
                        for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                        {
                            children[index].SetAsLastSibling();
                            children[index].anchoredPosition = new Vector2(children[index].anchoredPosition.x, children[children.Count - 1].anchoredPosition.y - gridLayoutGroup.cellSize.y - gridLayoutGroup.spacing.y);
                            //Debug.Log("这是格子的PosX" + children[index].anchoredPosition.x);
                            //Debug.Log("这是格子的PosY" + children[children.Count - 1]);
                            //Debug.Log("第几个啦" + gridLayoutGroup.constraintCount);
                            realIndex++;

                            if (realIndex > amount - 1)
                            {
                                children[index].gameObject.SetActive(false);
                            }
                            else
                            {
                                UpdateChildrenCallback(realIndex, children[index]);
                            }
                        }

                        //GridLayoutGroup 底部加长;
                        rectTransform.sizeDelta += new Vector2(0, gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);

                        //更新child;
                        for (int index = 0; index < children.Count; index++)
                        {
                            children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                        }
                    }
                }
            }
            else
            {
                //Debug.Log("Drag Down");
                //向下拉,下面收缩;
                if (realIndex + 1 <= children.Count)
                {
                    startPosition = currentPos;
                    return;
                }
                RectTransform scrollRectTransform = scrollRect.GetComponent<RectTransform>();
                Vector3 scrollRectAnchorBottom = new Vector3(0, -scrollRectTransform.rect.height - gridLayoutGroup.spacing.y, 0f);
                float scrollRectBottom = scrollRect.transform.TransformPoint(scrollRectAnchorBottom).y;

                Vector3 childUpLeft = new Vector3(children[children.Count - 1].anchoredPosition.x, children[children.Count - 1].anchoredPosition.y, 0f);

                float childUp = transform.TransformPoint(childUpLeft).y;

                if (childUp < scrollRectBottom)
                {
                    //Debug.Log("childUp < scrollRectBottom");

                    //把底部的一行 移动到顶部
                    for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                    {
                        children[children.Count - 1 - index].SetAsFirstSibling();

                        children[children.Count - 1 - index].anchoredPosition = new Vector2(children[children.Count - 1 - index].anchoredPosition.x, children[0].anchoredPosition.y + gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);

                        children[children.Count - 1 - index].gameObject.SetActive(true);

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

                    realIndex -= gridLayoutGroup.constraintCount;

                    //GridLayoutGroup 底部缩短;
                    rectTransform.sizeDelta -= new Vector2(0, gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);

                    //更新child;
                    for (int index = 0; index < children.Count; index++)
                    {
                        children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                    }
                }
            }
        }
        else
        {
            float offsetX = currentPos.x - startPosition.x;

            if (offsetX < 0)
            {
                //向左拉,向右扩展;
                {
                    if (realIndex >= amount - 1)
                    {
                        startPosition = currentPos;
                        return;
                    }

                    float scrollRectLeft = scrollRect.transform.TransformPoint(Vector3.zero).x;

                    Vector3 childBottomRight = new Vector3(children[0].anchoredPosition.x+ gridLayoutGroup.cellSize.x, children[0].anchoredPosition.y, 0f);
                    float childRight = transform.TransformPoint(childBottomRight).x;

                   // Debug.LogError("childRight=" + childRight);

                    if (childRight <= scrollRectLeft)
                    {
                        //Debug.Log("childRight <= scrollRectLeft");

                        //移动到右边;
                        for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                        {
                            children[index].SetAsLastSibling();

                            children[index].anchoredPosition = new Vector2(children[children.Count - 1].anchoredPosition.x + gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x, children[index].anchoredPosition.y);

                            realIndex++;

                            if (realIndex > amount - 1)
                            {
                                children[index].gameObject.SetActive(false);
                            }
                            else
                            {
                                UpdateChildrenCallback(realIndex, children[index]);
                            }
                        }

                        //GridLayoutGroup 右侧加长;
                        rectTransform.sizeDelta += new Vector2(gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x,0);

                        //更新child;
                        for (int index = 0; index < children.Count; index++)
                        {
                            children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                        }
                    }
                }
            }
            else
            {
                //Debug.Log("Drag Down");
                //向右拉,右边收缩;
                if (realIndex + 1 <= children.Count)
                {
                    startPosition = currentPos;
                    return;
                }
                RectTransform scrollRectTransform = scrollRect.GetComponent<RectTransform>();
                Vector3 scrollRectAnchorRight = new Vector3(scrollRectTransform.rect.width + gridLayoutGroup.spacing.x, 0, 0f);
                float scrollRectRight = scrollRect.transform.TransformPoint(scrollRectAnchorRight).x;

                Vector3 childUpLeft = new Vector3(children[children.Count - 1].anchoredPosition.x, children[children.Count - 1].anchoredPosition.y, 0f);

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

                if (childLeft >= scrollRectRight)
                {
                    //Debug.LogError("childLeft > scrollRectRight");

                    //把右边的一行 移动到左边;
                    for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                    {
                        children[children.Count - 1 - index].SetAsFirstSibling();

                        children[children.Count - 1 - index].anchoredPosition = new Vector2(children[0].anchoredPosition.x - gridLayoutGroup.cellSize.x - gridLayoutGroup.spacing.x,children[children.Count - 1 - index].anchoredPosition.y);

                        children[children.Count - 1 - index].gameObject.SetActive(true);

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

                    //GridLayoutGroup 右侧缩短;
                    rectTransform.sizeDelta -= new Vector2(gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x, 0);

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

                    realIndex -= gridLayoutGroup.constraintCount;
                }
            }
        }

        startPosition = currentPos;
    }

    void UpdateChildrenCallback(int index,Transform trans)
    {
        if (updateChildrenCallback != null)
        {
            updateChildrenCallback(index, trans);
        }
    }
    /// <summary>
    /// 设置总的个数;
    /// </summary>
    /// <param name="count"></param>
    public void SetAmount(int count)
    {
        amount = count;
        StartCoroutine(InitChildren());
    }
}

 

<think>嗯,用户想了解Excel中的VLOOKUP函数的用法和参数含义。首先,我需要回忆一下VLOOKUP的基本结构。VLOOKUP是垂直查找函数,用于在表格的首列查找指定的值,然后返回该行中指定列的数据。它的四个参数分别是查找值、表格范围、列索引号和匹配模式。 接下来,我得确认每个参数的具体作用。第一个参数是lookup_value,也就是用户要查找的值,比如产品ID或者姓名。第二个参数是table_array,即查找的范围,这里要注意的是,查找值必须位于这个范围的第一列,否则函数无法正确工作。第三个参数是col_index_num,也就是用户想要返回的数据在表格范围中的第几列,这个列数是从表格范围的第一列开始算起的,不是整个工作表的列。第四个参数是range_lookup,决定是精确匹配还是近似匹配,通常用FALSE或0来指定精确匹配,避免错误。 然后,用户可能需要一个具体的例子来理解如何使用。比如,假设有一个产品价格表,用户想根据产品ID查找对应的价格。这时候,VLOOKUP就可以在ID列查找,然后返回价格列的数据。同时,要提醒用户注意表格范围最好使用绝对引用,比如$A$2:$C$100,这样在拖动公式时范围不会变化。 可能遇到的问题也需要考虑。比如,如果查找值不在表格的第一列,或者列索引号超过了表格的列数,函数会返回错误。此外,数据格式不一致也可能导致问题,比如查找值是数字,而表格中是文本格式的数字,这时候需要统一格式。还有,当出现#N/A错误时,可能是查找值不存在,或者匹配模式设置不正确,需要检查参数是否正确。 用户可能还会问到如何避免常见的错误,比如部分数据匹配出错的情况。这时候需要检查是否有多余的空格,或者数据格式不一致,或者表格范围没有锁定导致拖动时偏移。此外,XLOOKUP作为VLOOKUP的升级版,可能在某些情况下更方便,比如可以向左查找或者返回多列数据,这也是可以提及的内容。 最后,整理步骤,从基础语法到参数说明,再到具体案例,逐步引导用户理解如何使用VLOOKUP函数。同时,提供常见错误和解决方法,帮助用户在实际应用中避免问题。如果有必要,还可以比较VLOOKUP和其他查找函数的区别,比如HLOOKUP或XLOOKUP,但根据用户的问题,主要集中在VLOOKUP本身即可。</think>### Excel VLOOKUP函数详解 #### 一、基础语法与参数说明 VLOOKUP函数的语法为: $$=VLOOKUP(lookup\_value, table\_array, col\_index\_num, [range\_lookup])$$ 包含4个参数: 1. **lookup_value**(必填):要查找的值(如单元格引用或具体值) 2. **table_array**(必填):包含数据的表格范围(必须包含查找列和返回列) 3. **col_index_num**(必填):返回值所在列的序号(从table_array第一列开始计数) 4. **range_lookup**(可选):匹配类型 - `TRUE`/`1`:近似匹配(默认值,需数据升序排列) - `FALSE`/`0`:精确匹配(常用选项) [^1][^2] #### 二、使用步骤演示(工资表查询案例) 假设需要根据员工编号查询工资: 1. 建立查询单元格(如`B12`) 2. 输入公式: ```excel =VLOOKUP(A12, $A$2:$D$100, 4, 0) ``` - `A12`:待查询的员工编号 - `$A$2:$D$100`:锁定数据区域(绝对引用) - `4`:返回第4列(工资列) - `0`:精确匹配 [^2][^3] #### 三、常见错误与解决方法 | 错误现象 | 原因 | 解决方案 | |---------|------|---------| | #N/A | 查找值不存在 | 检查数据源或改用`IFERROR`容错 | | #REF! | 列序号超出范围 | 确认col_index_num ≤ 表格列数 | | 部分匹配失败 | 数据格式不一致 | 统一数值/文本格式 | | 结果错位 | 表格未锁定 | 使用`$`符号固定区域引用 | [^3][^4] #### 四、进阶技巧 1. **多条件查询**: 使用辅助列合并多个条件字段 ```excel =VLOOKUP(A2&B2, $D$2:$F$100, 3, 0) ``` 2. **通配符匹配**: `"*"`匹配任意字符,`"?"`匹配单个字符 ```excel =VLOOKUP("张*", $A$2:$C$100, 3, 0) ``` 3. **跨表查询**: 引用其他工作表数据 ```excel =VLOOKUP(A2, Sheet2!$A$2:$D$100, 4, 0) ``` [^1][^4]
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值