NGUI 循环ScrollView

宰父焕
2023-12-01
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class BetterScrollView2 : MonoBehaviour {

    public GameObject template;
    public int cellWidth = 100;
    public int cellHeight = 100;
    public int dataCount = 33;
    public int maxCellCount; //这个ScrollView多少个滚动单位(排或者列)可以出现头和尾有一端隐藏的效果
    public UIScrollView scrollView;
    public GameObject dragScrollViewCollider;
    public List<ScrollViewUnitData> lisScrollUnits = new List<ScrollViewUnitData>();
    /// <summary>
    /// 展示完所有数据需要多少个滚动单位
    /// </summary>
    public int needCellUnitsCount;
    /// <summary>
    /// 每个滚动单位(一排或者一列)的格子数
    /// </summary>
    public int cellCountPerScrollUnit=4;

    // Use this for initialization
    void Start() {
        UIEventListener.Get(dragScrollViewCollider).onDrag += OnDragScrollView;
        template.SetActive(false);
    }

   

    // Update is called once per frame
    void Update() {
        if (Input.GetKeyUp(KeyCode.Space)) {
            CheckDataChange();
        }
    }

    /// <summary>
    /// 刷新数据,这个应该是在数据列表发生改变的时候调用一次
    /// </summary>
    void CheckDataChange() {
        needCellUnitsCount = Mathf.CeilToInt((float)dataCount / (float)cellCountPerScrollUnit);
       
           
        ///数据量需要的滚动单位数的时候 最多生成到最大单位数
        if (needCellUnitsCount > lisScrollUnits.Count) {
            while (lisScrollUnits.Count < maxCellCount && lisScrollUnits.Count < needCellUnitsCount) {
                ScrollViewUnitData scrollViewUnit = GetScrollViewUnit(lisScrollUnits.Count);
                lisScrollUnits.Add(scrollViewUnit);
            }

        }
        else if (needCellUnitsCount < lisScrollUnits.Count)
        ///当数据量小于格子数的时候,删除掉多余的格子
        {
            while (lisScrollUnits.Count > needCellUnitsCount) {
                lisScrollUnits[0].DestroyThisUnit();
                lisScrollUnits.RemoveAt(0);
            }
        }
        else {//数据量没变  不用管   后面的全部重新赋值就行

        }

           
        ///数据量发生改变了 按照列表顺序从新给每个格子赋予数据索引
        for (int i = 0; i < lisScrollUnits.Count; i++) {
            ScrollViewUnitData unit = lisScrollUnits[i];
            unit.SetDataIndex(i, cellCountPerScrollUnit, dataCount);
            unit.SetPosition( i * cellHeight * Vector3.down,cellWidth,cellHeight);
              
        }
        //重新赋值之后要重置ScrollView位置
        scrollView.ResetPosition();
        
    }



    ScrollViewUnitData GetScrollViewUnit(int unitIndex) {
        
        List<ScrollViewCellData> cellDatas = new List<ScrollViewCellData>();
        for (int i = 0; i < cellCountPerScrollUnit; i++) {
            GameObject cell = Instantiate(template) as GameObject;
            cell.name = "Cell" + unitIndex + i;
            cell.transform.parent = template.transform.parent;
            cell.transform.localScale = template.transform.localScale;
            ScrollViewCellData cellData = new ScrollViewCellData();
            cellData.cellObj = cell;
            cellDatas.Add(cellData);
        }
        ScrollViewUnitData scrollUnit = new ScrollViewUnitData();
        scrollUnit.listCells = cellDatas;
        return scrollUnit;
    }


    void OnDragScrollView(GameObject obj, Vector2 delta) {
        CheckCellSwap(delta);
    }
    /// <summary>
    /// 检测是否需要前后置换格子来显示数据
    /// </summary>
    void CheckCellSwap(Vector2 delta) {

        if (lisScrollUnits.Count > 0) {
            ScrollViewUnitData firstCellUnit = lisScrollUnits[0].CopyUnit();
            ScrollViewUnitData lastCellUnit = lisScrollUnits[lisScrollUnits.Count - 1].CopyUnit();
            if (delta.y > 0) {//向上拖动
                ///最后一个滚动单位还不是索引到最后一个单位(排/列)数据 把第一个补到最后去
                if (lastCellUnit.unitIndex != needCellUnitsCount - 1 && (firstCellUnit.visible == false)) {
                    lisScrollUnits.RemoveAt(0);
                    firstCellUnit.SetPosition( lastCellUnit.Position + Vector3.down * cellHeight,cellWidth,cellHeight);
                    firstCellUnit.SetDataIndex(lastCellUnit.unitIndex + 1,cellCountPerScrollUnit,dataCount);
                    lisScrollUnits.Add(firstCellUnit);
                }
            }
            else {
                ///第一个滚动单位还不是对应第一单位数据 把最后补到第一个去
                if (firstCellUnit.unitIndex != 0 && lastCellUnit.visible == false) {

                    lastCellUnit.SetPosition( firstCellUnit.Position - Vector3.down * cellHeight,cellWidth,cellHeight);
                    lastCellUnit.SetDataIndex(firstCellUnit.unitIndex - 1, cellCountPerScrollUnit, dataCount);
                   
                    ///因为List没有直接把一个数据直接加到列表前面的方法,索引这个先把第一个以后的数据往后移动一位
                    for (int i = lisScrollUnits.Count - 1; i > 0; i--) {
                        lisScrollUnits[i] = lisScrollUnits[i - 1];
                    }
                    lisScrollUnits[0] = lastCellUnit;
                }
            }

        }
    }
}
/// <summary>
/// 每个滚动单位(一排或者一列)
/// </summary>
[System.Serializable]
public class ScrollViewUnitData {
   
    public ScrollViewUnitData() {

    }

    /// <summary>
    /// 根据当前的数据复制一份新的单位
    /// </summary>
    /// <returns></returns>
    public ScrollViewUnitData CopyUnit() {
        ScrollViewUnitData unitNew = new ScrollViewUnitData();
        unitNew.listCells = listCells;
        unitNew.mUnitIndex = mUnitIndex;
        return unitNew;
    }
    /// <summary>
    /// 以第一个格子的可见性来判断这一个单位的可见性
    /// </summary>
    public bool visible {
        get {
            return listCells[0].visible;
        }
    }
    /// <summary>
    /// 这个单位绑定的格子
    /// </summary>
    public List<ScrollViewCellData> listCells = new List<ScrollViewCellData>();
    public int unitIndex {
        get {
           return  mUnitIndex;
        }
    }
    [SerializeField]
    private int mUnitIndex;
    /// <summary>
    /// 设置这个滚动单位的数据索引 格子的数据索引逐一递增
    /// </summary>
    public void SetDataIndex(int unitIndex,int cellCountPerUnit,int maxDataIndex) {
        mUnitIndex = unitIndex;
        
        for (int cellIndex = 0; cellIndex < listCells.Count; cellIndex++) {
            ScrollViewCellData cell = listCells[cellIndex];

            cell.dataIndex = mUnitIndex*cellCountPerUnit+cellIndex;
            ///这个格子还是有数据对应的
            if (cell.dataIndex < maxDataIndex) {
                cell.SetShowState(true);
                cell.RefreshData();
            }
            else {
                //没有数据对应,隐藏
                cell.SetShowState(false);
            }
        }
    }
    
    /// <summary>
    /// 返回的是这个单位的第一行或者第一列的本地坐标,
    /// </summary>
    public Vector3 Position {
        get {
            return listCells[0].cellObj.transform.localPosition;
        }
    }
    /// <summary>
    /// 设置的时候传进来第一个格子的坐标后面的格子根据指定的格子宽高排位置
    /// </summary>
    public void  SetPosition(Vector3 localPos, int cellWidth, int cellHeight) {
          for (int i = 0; i < listCells.Count; i++) {
              listCells[i].cellObj.transform.localPosition =cellWidth * i*Vector3.right+ localPos  ;
          }
    }

    /// <summary>
    /// 删除这个单位对应的所有格子
    /// </summary>
    public void DestroyThisUnit() {
        for (int i = 0; i < listCells.Count; i++) {
            listCells[i].Destroy();
        }
    }
}



/// <summary>
/// 滚动面板一个格子需要的数据
/// </summary>
[System.Serializable]
public class ScrollViewCellData {
    public GameObject cellObj;
    /// <summary>
    /// 这个格子对应的数据索引
    /// </summary>
    public int dataIndex;


    public void RefreshData() {
        cellObj.GetComponent<UILabel>().text = dataIndex.ToString();
        ;
    }
    public Vector3 position {
        get {
            return cellObj.transform.localPosition;
        }
        set {
            cellObj.transform.localPosition = value;
        }
    }
    public bool visible {
        get {
            return cellObj.GetComponent<UIWidget>().isVisible;
        }
    }

    public ScrollViewCellData(GameObject obj, int _dataIndex) {
        cellObj = obj;
        dataIndex = _dataIndex;
    }

    public ScrollViewCellData() {

    }
    /// <summary>
    /// 设置显示或者隐藏格子
    /// </summary>
    /// <param name="bShow"></param>
    public void SetShowState(bool bShow) {
        cellObj.SetActive(bShow);
    }
    public void Destroy() {
        if (cellObj)
            Object.Destroy(cellObj);
    }
}

 类似资料: