Unity 通过对象池实现滑动列表

背包格子类

挂载在格子的预制体上,用于创建该格子时更新该物品的数量等信息

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

public class BagItem : MonoBehaviour
{
    public void InitItemInfo(Item info)
    {
        //更新道具数量
        GetComponentInChildren<Text>().text = info.num.ToString();
    }
}

背包管理器

包含物品类,物品列表,以及创建演示数据的函数

using System.Collections.Generic;

public class Item
{
    public int id;
    public int num;
}

public class BagManager: Singleton<BagManager>
{
    public List<Item> items = new List<Item>();

    public void InitItemsInfo()
    {
        for(int i = 1; i <= 100; i++)
        {
            Item item = new Item();
            item.id = i;
            item.num = i;
            items.Add(item);
        }
    }
}

单例类

各种Manager类继承此类之后,可以方便地通过单例获取到该Manager类里的成员

public class Singleton<T> where T : new()
{
    private static T _instance;
    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new T();
            }
            return _instance;
        }
    }
}

背包面板

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

public class BagPanel : BasePanel
{
    static readonly string path = "Prefabs/UI/BagPanel";

    public BagPanel() : base(new PanelType(path)) { }

    /*-----------可配置的参数-----------*/

    public int column = 4;                  //列数
    public float itemSize = 180;            //物品格子大小
    public float interval = 10;             //格子之间的间隙
    public float viewPortHeight = 950;      //窗口的高度

    //记录上一次显示的最值索引,以便移除看不见的格子
    int lastMinDisplayIndex;        
    int lastMaxDisplayIndex;
    //滑动列表的容器
    public RectTransform content;
    //存储当前显示的物品及编号
    Dictionary<int, GameObject> curDisplayItems = new Dictionary<int, GameObject>();
    
    public void DisplayBagItem()
    {
        /*-----------计算可见范围-----------*/
        
        int minDisplayIndex = (int)(content.anchoredPosition.y / (itemSize + interval)) * column;      //向下取整: 0,0 190,3 950,15
        int maxDisplayIndex = (int)((content.anchoredPosition.y + viewPortHeight) / (itemSize + interval)) * column + column; // 下面一栏物品,露出一点点也需要显示,所以需要多显示一行

        /*-----------越界的不显示-----------*/

        if (minDisplayIndex < 0)
            minDisplayIndex = 0;

        if (maxDisplayIndex >= BagManager.Instance.items.Count)
            maxDisplayIndex = BagManager.Instance.items.Count;

        /*---------显示可见范围内的格子------*/

        for (int i = minDisplayIndex;i < maxDisplayIndex; i++)
        {
            if (curDisplayItems.ContainsKey(i))                 //已显示的格子,不再重复创建
                continue;
            else
            {
                GameObject obj = PoolManager.Instance.getObject("BagItem", "Prefabs/UI/BagItem");       //未显示的格子,从池中获取
                obj.transform.SetParent(content);
                obj.transform.localPosition = new Vector3(i % column * (itemSize+interval), i / column * (itemSize + interval) * (-1), 0);          //将格子放到正确的位置上
                obj.GetComponent<BagItem>().InitItemInfo(BagManager.Instance.items[i]);                 //初始化格子信息
                curDisplayItems[i] = obj;                                                               //将当前显示的格子按照编号录入字典
            }
        }

        /*----------移除不可见的格子---------*/
        
        for(int i = lastMaxDisplayIndex;i > maxDisplayIndex;i--)
        {
            if (curDisplayItems.ContainsKey(i))
            {
                PoolManager.Instance.recycleObject("BagItem", curDisplayItems[i]);
                curDisplayItems.Remove(i);
            }
        }

        for(int i = lastMinDisplayIndex;i<minDisplayIndex;i++)
        {
            if (curDisplayItems.ContainsKey(i))
            {
                PoolManager.Instance.recycleObject("BagItem", curDisplayItems[i]);
                curDisplayItems.Remove(i);
            }
        }

        lastMaxDisplayIndex = maxDisplayIndex;
        lastMinDisplayIndex = minDisplayIndex;
    }

    public override void OnEnter()
    {
        BagManager.Instance.InitItemsInfo();                                                    //生成格子的演示数据
        content = panelBindingTool.GetOrAddComponentInChildren<RectTransform>("Content");       //获取容器的组件
        content.sizeDelta = new Vector2(0, Mathf.CeilToInt(BagManager.Instance.items.Count / column) * (itemSize + interval));      //根据物品数目计算容器的高度(向上取整)

        panelBindingTool.GetOrAddComponentInChildren<Button>("关闭").onClick.AddListener( ()=>
        {
            panelStack.Pop();
        }
        );

        GameManager.instance.NonMonoUpdateMethod = DisplayBagItem;      //将DisplayBagItem函数注入GameManager的Update中,实现实时更新
    }

    public override void OnExit()
    {
        panelManager.DestroyPanel(this.panelType);
    }

    public override void OnPause()
    {
        panelBindingTool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false;
    }

    public override void OnResume()
    {
        panelBindingTool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = true;
    }
}

效果

猜你喜欢

转载自blog.csdn.net/weixin_43673589/article/details/123941147
今日推荐