0评论

Unity3D界面管理——无限列表(基于UGUI)

文章来自https://blog.csdn.net/qq_28474981/article/details/82749369 2019-02-18 357浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏开发行业精英群711501594

在开发过程中需要做界面管理,这里就分享下基于UGUI实现无限列表的方法。

主要思路:

1.根据列表项的大小与可视框生成大于可视框一个数量的列表项
2.根据列表项距离可视框中间的距离进行上下切换(使用数据结构为链表)
3.根据滚动距离做累加,求得当前的索引值,并通过索引值获取对应数据对列表项赋值

验证:提供有边界和无边界两种虚拟列表

1.有边界的列表将会在临界值(0或者1000)无法向上一个索引值(0)或下一个索引值(1000)滚动
2.无边界的列表将会在临界值时进行循环滚动


列表:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
/// <summary>
/// 虚拟列表
/// </summary>
public class VirtualList : MonoBehaviour, IScrollHandler
{
    /// <summary>
    /// 元件尺寸
    /// </summary>
    public Vector2 ItemSize;
    /// <summary>
    /// 放置内容
    /// </summary>
    public RectTransform Content;
    /// <summary>
    /// 列表项缓存
    /// </summary>
    private LinkedList<VirtualListItem> virtualListItems;
    public List<VirtualListItemData> DataList = new List<VirtualListItemData>();
    /// <summary>
    /// 列表单元预制体
    /// </summary>
    [SerializeField]
    private GameObject ListItemPrefab;
    /// <summary>
    /// 当前的中心二维坐标
    /// </summary>
    private Vector2 curCenterPos;
    /// <summary>
    /// 初始的中心二维坐标
    /// </summary>
    private Vector2 originCenterPos;
    /// <summary>
    /// 行数
    /// </summary>
    private uint VirtualRow;
    private Vector2 TopPos;
    private Vector2 LastPos;
    public uint CanViewNum;
    /// <summary>
    /// 每次的偏移量
    /// </summary>
    private Vector2 deltaPos;
    public bool HasEdge = true;
    public void Start()
    {
        curCenterPos.y += Content.rect.height / 2;
        LastPos.y = -200;
        Debug.Log(LastPos.y);
        originCenterPos.y = Content.rect.height / 2;
        VirtualRow = CanViewNum+1;
        TopPos.y =200;
        virtualListItems = new LinkedList<VirtualListItem>();
        InitData();
        for (int i = 0; i < VirtualRow; i++)
        {
            VirtualListItem temp = MonoBehaviour.Instantiate(ListItemPrefab, Content).GetComponent<VirtualListItem>();
            virtualListItems.AddLast(temp);
            temp.Init(this);
            temp.SetIndex(i, 1);
            temp.BindData(DataList[i]);
        }
    }
    public void InitData()
    {
        for(int i = 0; i < 1001; i++)
        {
            DataList.Add(new VirtualListItemData(i.ToString(),i));
        }
    }
    private void CalculatePosistion(VirtualListItem item)
    {
        float tempPosY = deltaPos.y + item.transform.localPosition.y;
        Vector3 tempPos = item.transform.localPosition;
        item.transform.localPosition = new Vector3(item.transform.localPosition.x, tempPosY,item.transform.localPosition.z);
        if (tempPosY < LastPos.y*1.5)
        {
            if (HasEdge&& virtualListItems.First.Value.Data.CurIndex - 1 < 0)
            {
                return;
            }
            int index = virtualListItems.First.Value.Data.CurIndex - 1;
            if (index < 0)
                index += DataList.Count;
            LinkedListNode<VirtualListItem> tempNode = virtualListItems.Last;
            tempNode.Value.transform.localPosition = new Vector3(virtualListItems.First.Value.transform.localPosition.x,
                virtualListItems.First.Value.transform.localPosition.y + item.SizeY,
                virtualListItems.First.Value.transform.localPosition.z);
            virtualListItems.RemoveLast();
            tempNode.Value.BindData(DataList[index]);
            virtualListItems.AddFirst(tempNode);
        }
        if (tempPosY > TopPos.y * 1.5)
        {
            if (HasEdge && virtualListItems.Last.Value.Data.CurIndex +1> DataList.Count - 1)
            {
                return;
            }
            int index = virtualListItems.Last.Value.Data.CurIndex + 1;
            if (index > DataList.Count - 1)
                index = index-(DataList.Count);
            LinkedListNode<VirtualListItem> tempNode = virtualListItems.First;
            tempNode.Value.transform.position = new Vector3(virtualListItems.Last.Value.transform.position.x,
                virtualListItems.Last.Value.transform.position.y - item.SizeY,
                virtualListItems.Last.Value.transform.position.z);
            virtualListItems.RemoveFirst();
            tempNode.Value.BindData(DataList[index]);
            virtualListItems.AddLast(tempNode);
        }
    }
    public void OnScroll(PointerEventData eventData)
    {
        deltaPos.y = eventData.scrollDelta.y*30;
        Debug.Log(deltaPos.y);
        LinkedListNode<VirtualListItem> node = virtualListItems.First;
        if (HasEdge)
        {
            if (virtualListItems.First.Value.TotalIndex == 0 && deltaPos.y < 0 && virtualListItems.First.Value.transform.localPosition.y < TopPos.y)
            {
                return;
            }
            if (virtualListItems.Last.Value.TotalIndex == DataList.Count - 1 && deltaPos.y > 0 && virtualListItems.Last.Value.transform.localPosition.y > LastPos.y - 30)
            {
                return;
            }
        }
        bool isForeachFinish = false;
        while (node != null && !isForeachFinish)
        {
            if (node == virtualListItems.Last)
            {
                isForeachFinish = true;
            }
            CalculatePosistion(node.Value);
            node = node.Next;
        }
    }
}

列表项:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class VirtualListItem : MonoBehaviour
{
    public VirtualList CurList;
    public float SizeY { get; private set; }
    public float SizeX { get; private set; }
    public int RowIndex { get; private set; }
    public int ColIndex { get; private set; }
    public int TotalIndex { get { return Data.CurIndex; } }
    [SerializeField]
    private RectTransform curRectTransform;
    public Text IndexText;
    public VirtualListItemData Data;
    public void Init(VirtualList list)
    {
        CurList = list;
        SizeY = curRectTransform.rect.height;
        SizeX = curRectTransform.rect.width;
    }
    public void SetIndex(int rowIndex, int colIndex)
    {
        RowIndex = rowIndex;
        ColIndex = colIndex;
        Debug.Log(CurList.Content.rect.y);
        curRectTransform.localPosition = new Vector2(0, -4*CurList.Content.rect.y/ CurList.CanViewNum - (rowIndex * SizeY));
    }
    public void SetContent(string content)
    {
        IndexText.text = content;
    }
    public void BindData(VirtualListItemData data)
    {
        this.Data = data;
        IndexText.text = data.Content.ToString();
    }
}

列表数据接口:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class VirtualListItemData 
{
    public object Content { get; set; }
    public int CurIndex { get; set; }
    public VirtualListItemData(object content,int index)
    {
        Content = content;
        CurIndex = index;
    }
}